183. Araxis Merge File Comparison Report

Produced by Araxis Merge on 2023-03-13 03:01:04 +0000. See www.araxis.com for information about Merge. This report uses XHTML and CSS2, and is best viewed with a modern standards-compliant browser. For optimum results when printing this report, use landscape orientation and enable printing of background images and colours in your browser.

183.1 Files compared

#LocationFileLast Modified
1Porto v4.0.4/Porto Theme/app/code/Smartwave/Porto/view/frontend/web/jspackery.pkgd.js2016-01-16 15:06:58 +0000
2Porto v4.0.5/Porto Theme/app/code/Smartwave/Porto/view/frontend/web/jspackery.pkgd.js2016-01-16 15:06:58 +0000

183.2 Comparison summary

DescriptionBetween
Files 1 and 2
Text BlocksLines
Unchanged18178
Changed00
Inserted00
Removed00

183.3 Comparison options

WhitespaceConsecutive whitespace is treated as a single space
Character caseDifferences in character case are significant
Line endingsDifferences in line endings (CR and LF characters) are ignored
CR/LF charactersNot shown in the comparison detail
Active line-pairing rules

183.4 Active regular expressions

No regular expressions were active.

183.5 Comparison detail

1 /*! 1 /*!
2  * Packery PACKAGED v1.4.3 2  * Packery PACKAGED v1.4.3
3  * bin-packing layout library 3  * bin-packing layout library
4  * 4  *
5  * Licensed GPLv3 for open source use 5  * Licensed GPLv3 for open source use
6  * or Flickity Commercial License for commercial use 6  * or Flickity Commercial License for commercial use
7  * 7  *
8  * http://packery.metafizzy.co 8  * http://packery.metafizzy.co
9  * Copyright 2015 Metafizzy 9  * Copyright 2015 Metafizzy
10  */ 10  */
11  11 
12 /** 12 /**
13  * Bridget makes jQuery widgets 13  * Bridget makes jQuery widgets
14  * v1.1.0 14  * v1.1.0
15  * MIT license 15  * MIT license
16  */ 16  */
17  17 
18 ( function( window ) { 18 ( function( window ) {
19  19 
20  20 
21  21 
22 // -------------------------- utils -------------------------- // 22 // -------------------------- utils -------------------------- //
23  23 
24 var slice = Array.prototype.slice; 24 var slice = Array.prototype.slice;
25  25 
26 function noop() {} 26 function noop() {}
27  27 
28 // -------------------------- definition -------------------------- // 28 // -------------------------- definition -------------------------- //
29  29 
30 function defineBridget( $ ) { 30 function defineBridget( $ ) {
31  31 
32 // bail if no jQuery 32 // bail if no jQuery
33 if ( !$ ) { 33 if ( !$ ) {
34   return; 34   return;
35 } 35 }
36  36 
37 // -------------------------- addOptionMethod -------------------------- // 37 // -------------------------- addOptionMethod -------------------------- //
38  38 
39 /** 39 /**
40  * adds option method -> $().plugin('option', {...}) 40  * adds option method -> $().plugin('option', {...})
41  * @param {Function} PluginClass - constructor class 41  * @param {Function} PluginClass - constructor class
42  */ 42  */
43 function addOptionMethod( PluginClass ) { 43 function addOptionMethod( PluginClass ) {
44   // don't overwrite original option method 44   // don't overwrite original option method
45   if ( PluginClass.prototype.option ) { 45   if ( PluginClass.prototype.option ) {
46     return; 46     return;
47   } 47   }
48  48 
49   // option setter 49   // option setter
50   PluginClass.prototype.option = function( opts ) { 50   PluginClass.prototype.option = function( opts ) {
51     // bail out if not an object 51     // bail out if not an object
52     if ( !$.isPlainObject( opts ) ){ 52     if ( !$.isPlainObject( opts ) ){
53       return; 53       return;
54     } 54     }
55     this.options = $.extend( true, this.options, opts ); 55     this.options = $.extend( true, this.options, opts );
56   }; 56   };
57 } 57 }
58  58 
59 // -------------------------- plugin bridge -------------------------- // 59 // -------------------------- plugin bridge -------------------------- //
60  60 
61 // helper function for logging errors 61 // helper function for logging errors
62 // $.error breaks jQuery chaining 62 // $.error breaks jQuery chaining
63 var logError = typeof console === 'undefined' ? noop : 63 var logError = typeof console === 'undefined' ? noop :
64   function( message ) { 64   function( message ) {
65     console.error( message ); 65     console.error( message );
66   }; 66   };
67  67 
68 /** 68 /**
69  * jQuery plugin bridge, access methods like $elem.plugin('method') 69  * jQuery plugin bridge, access methods like $elem.plugin('method')
70  * @param {String} namespace - plugin name 70  * @param {String} namespace - plugin name
71  * @param {Function} PluginClass - constructor class 71  * @param {Function} PluginClass - constructor class
72  */ 72  */
73 function bridge( namespace, PluginClass ) { 73 function bridge( namespace, PluginClass ) {
74   // add to jQuery fn namespace 74   // add to jQuery fn namespace
75   $.fn[ namespace ] = function( options ) { 75   $.fn[ namespace ] = function( options ) {
76     if ( typeof options === 'string' ) { 76     if ( typeof options === 'string' ) {
77       // call plugin method when first argument is a string 77       // call plugin method when first argument is a string
78       // get arguments for method 78       // get arguments for method
79       var args = slice.call( arguments, 1 ); 79       var args = slice.call( arguments, 1 );
80  80 
81       for ( var i=0, len = this.length; i < len; i++ ) { 81       for ( var i=0, len = this.length; i < len; i++ ) {
82         var elem = this[i]; 82         var elem = this[i];
83         var instance = $.data( elem, namespace ); 83         var instance = $.data( elem, namespace );
84         if ( !instance ) { 84         if ( !instance ) {
85           logError( "cannot call methods on " + namespace + " prior to initialization; " + 85           logError( "cannot call methods on " + namespace + " prior to initialization; " +
86             "attempted to call '" + options + "'" ); 86             "attempted to call '" + options + "'" );
87           continue; 87           continue;
88         } 88         }
89         if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) { 89         if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
90           logError( "no such method '" + options + "' for " + namespace + " instance" ); 90           logError( "no such method '" + options + "' for " + namespace + " instance" );
91           continue; 91           continue;
92         } 92         }
93  93 
94         // trigger method with arguments 94         // trigger method with arguments
95         var returnValue = instance[ options ].apply( instance, args ); 95         var returnValue = instance[ options ].apply( instance, args );
96  96 
97         // break look and return first value if provided 97         // break look and return first value if provided
98         if ( returnValue !== undefined ) { 98         if ( returnValue !== undefined ) {
99           return returnValue; 99           return returnValue;
100         } 100         }
101       } 101       }
102       // return this if no return value 102       // return this if no return value
103       return this; 103       return this;
104     } else { 104     } else {
105       return this.each( function() { 105       return this.each( function() {
106         var instance = $.data( this, namespace ); 106         var instance = $.data( this, namespace );
107         if ( instance ) { 107         if ( instance ) {
108           // apply options & init 108           // apply options & init
109           instance.option( options ); 109           instance.option( options );
110           instance._init(); 110           instance._init();
111         } else { 111         } else {
112           // initialize new instance 112           // initialize new instance
113           instance = new PluginClass( this, options ); 113           instance = new PluginClass( this, options );
114           $.data( this, namespace, instance ); 114           $.data( this, namespace, instance );
115         } 115         }
116       }); 116       });
117     } 117     }
118   }; 118   };
119  119 
120 } 120 }
121  121 
122 // -------------------------- bridget -------------------------- // 122 // -------------------------- bridget -------------------------- //
123  123 
124 /** 124 /**
125  * converts a Prototypical class into a proper jQuery plugin 125  * converts a Prototypical class into a proper jQuery plugin
126  *   the class must have a ._init method 126  *   the class must have a ._init method
127  * @param {String} namespace - plugin name, used in $().pluginName 127  * @param {String} namespace - plugin name, used in $().pluginName
128  * @param {Function} PluginClass - constructor class 128  * @param {Function} PluginClass - constructor class
129  */ 129  */
130 $.bridget = function( namespace, PluginClass ) { 130 $.bridget = function( namespace, PluginClass ) {
131   addOptionMethod( PluginClass ); 131   addOptionMethod( PluginClass );
132   bridge( namespace, PluginClass ); 132   bridge( namespace, PluginClass );
133 }; 133 };
134  134 
135 return $.bridget; 135 return $.bridget;
136  136 
137 } 137 }
138  138 
139 // transport 139 // transport
140 if ( typeof define === 'function' && define.amd ) { 140 if ( typeof define === 'function' && define.amd ) {
141   // AMD 141   // AMD
142   define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget ); 142   define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget );
143 } else if ( typeof exports === 'object' ) { 143 } else if ( typeof exports === 'object' ) {
144   defineBridget( require('jquery') ); 144   defineBridget( require('jquery') );
145 } else { 145 } else {
146   // get jquery from browser global 146   // get jquery from browser global
147   defineBridget( window.jQuery ); 147   defineBridget( window.jQuery );
148 } 148 }
149 defineBridget( window.jQuery ); 149 defineBridget( window.jQuery );
150 })( window ); 150 })( window );
151  151 
152 /*! 152 /*!
153  * classie v1.0.1 153  * classie v1.0.1
154  * class helper functions 154  * class helper functions
155  * from bonzo https://github.com/ded/bonzo 155  * from bonzo https://github.com/ded/bonzo
156  * MIT license 156  * MIT license
157  *  157  * 
158  * classie.has( elem, 'my-class' ) -> true/false 158  * classie.has( elem, 'my-class' ) -> true/false
159  * classie.add( elem, 'my-new-class' ) 159  * classie.add( elem, 'my-new-class' )
160  * classie.remove( elem, 'my-unwanted-class' ) 160  * classie.remove( elem, 'my-unwanted-class' )
161  * classie.toggle( elem, 'my-class' ) 161  * classie.toggle( elem, 'my-class' )
162  */ 162  */
163  163 
164 /*jshint browser: true, strict: true, undef: true, unused: true */ 164 /*jshint browser: true, strict: true, undef: true, unused: true */
165 /*global define: false, module: false */ 165 /*global define: false, module: false */
166  166 
167 ( function( window ) { 167 ( function( window ) {
168  168 
169  169 
170  170 
171 // class helper functions from bonzo https://github.com/ded/bonzo 171 // class helper functions from bonzo https://github.com/ded/bonzo
172  172 
173 function classReg( className ) { 173 function classReg( className ) {
174   return new RegExp("(^|\\s+)" + className + "(\\s+|$)"); 174   return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
175 } 175 }
176  176 
177 // classList support for class management 177 // classList support for class management
178 // altho to be fair, the api sucks because it won't accept multiple classes at once 178 // altho to be fair, the api sucks because it won't accept multiple classes at once
179 var hasClass, addClass, removeClass; 179 var hasClass, addClass, removeClass;
180  180 
181 if ( 'classList' in document.documentElement ) { 181 if ( 'classList' in document.documentElement ) {
182   hasClass = function( elem, c ) { 182   hasClass = function( elem, c ) {
183     return elem.classList.contains( c ); 183     return elem.classList.contains( c );
184   }; 184   };
185   addClass = function( elem, c ) { 185   addClass = function( elem, c ) {
186     elem.classList.add( c ); 186     elem.classList.add( c );
187   }; 187   };
188   removeClass = function( elem, c ) { 188   removeClass = function( elem, c ) {
189     elem.classList.remove( c ); 189     elem.classList.remove( c );
190   }; 190   };
191 } 191 }
192 else { 192 else {
193   hasClass = function( elem, c ) { 193   hasClass = function( elem, c ) {
194     return classReg( c ).test( elem.className ); 194     return classReg( c ).test( elem.className );
195   }; 195   };
196   addClass = function( elem, c ) { 196   addClass = function( elem, c ) {
197     if ( !hasClass( elem, c ) ) { 197     if ( !hasClass( elem, c ) ) {
198       elem.className = elem.className + ' ' + c; 198       elem.className = elem.className + ' ' + c;
199     } 199     }
200   }; 200   };
201   removeClass = function( elem, c ) { 201   removeClass = function( elem, c ) {
202     elem.className = elem.className.replace( classReg( c ), ' ' ); 202     elem.className = elem.className.replace( classReg( c ), ' ' );
203   }; 203   };
204 } 204 }
205  205 
206 function toggleClass( elem, c ) { 206 function toggleClass( elem, c ) {
207   var fn = hasClass( elem, c ) ? removeClass : addClass; 207   var fn = hasClass( elem, c ) ? removeClass : addClass;
208   fn( elem, c ); 208   fn( elem, c );
209 } 209 }
210  210 
211 var classie = { 211 var classie = {
212   // full names 212   // full names
213   hasClass: hasClass, 213   hasClass: hasClass,
214   addClass: addClass, 214   addClass: addClass,
215   removeClass: removeClass, 215   removeClass: removeClass,
216   toggleClass: toggleClass, 216   toggleClass: toggleClass,
217   // short names 217   // short names
218   has: hasClass, 218   has: hasClass,
219   add: addClass, 219   add: addClass,
220   remove: removeClass, 220   remove: removeClass,
221   toggle: toggleClass 221   toggle: toggleClass
222 }; 222 };
223  223 
224 // transport 224 // transport
225 if ( typeof define === 'function' && define.amd ) { 225 if ( typeof define === 'function' && define.amd ) {
226   // AMD 226   // AMD
227   define( 'classie/classie',classie ); 227   define( 'classie/classie',classie );
228 } else if ( typeof exports === 'object' ) { 228 } else if ( typeof exports === 'object' ) {
229   // CommonJS 229   // CommonJS
230   module.exports = classie; 230   module.exports = classie;
231 } else { 231 } else {
232   // browser global 232   // browser global
233   window.classie = classie; 233   window.classie = classie;
234 } 234 }
235  235 
236 })( window ); 236 })( window );
237  237 
238 /*! 238 /*!
239  * getStyleProperty v1.0.4 239  * getStyleProperty v1.0.4
240  * original by kangax 240  * original by kangax
241  * http://perfectionkills.com/feature-testing-css-properties/ 241  * http://perfectionkills.com/feature-testing-css-properties/
242  * MIT license 242  * MIT license
243  */ 243  */
244  244 
245 /*jshint browser: true, strict: true, undef: true */ 245 /*jshint browser: true, strict: true, undef: true */
246 /*global define: false, exports: false, module: false */ 246 /*global define: false, exports: false, module: false */
247  247 
248 ( function( window ) { 248 ( function( window ) {
249  249 
250  250 
251  251 
252 var prefixes = 'Webkit Moz ms Ms O'.split(' '); 252 var prefixes = 'Webkit Moz ms Ms O'.split(' ');
253 var docElemStyle = document.documentElement.style; 253 var docElemStyle = document.documentElement.style;
254  254 
255 function getStyleProperty( propName ) { 255 function getStyleProperty( propName ) {
256   if ( !propName ) { 256   if ( !propName ) {
257     return; 257     return;
258   } 258   }
259  259 
260   // test standard property first 260   // test standard property first
261   if ( typeof docElemStyle[ propName ] === 'string' ) { 261   if ( typeof docElemStyle[ propName ] === 'string' ) {
262     return propName; 262     return propName;
263   } 263   }
264  264 
265   // capitalize 265   // capitalize
266   propName = propName.charAt(0).toUpperCase() + propName.slice(1); 266   propName = propName.charAt(0).toUpperCase() + propName.slice(1);
267  267 
268   // test vendor specific properties 268   // test vendor specific properties
269   var prefixed; 269   var prefixed;
270   for ( var i=0, len = prefixes.length; i < len; i++ ) { 270   for ( var i=0, len = prefixes.length; i < len; i++ ) {
271     prefixed = prefixes[i] + propName; 271     prefixed = prefixes[i] + propName;
272     if ( typeof docElemStyle[ prefixed ] === 'string' ) { 272     if ( typeof docElemStyle[ prefixed ] === 'string' ) {
273       return prefixed; 273       return prefixed;
274     } 274     }
275   } 275   }
276 } 276 }
277  277 
278 // transport 278 // transport
279 if ( typeof define === 'function' && define.amd ) { 279 if ( typeof define === 'function' && define.amd ) {
280   // AMD 280   // AMD
281   define( 'get-style-property/get-style-property',[],function() { 281   define( 'get-style-property/get-style-property',[],function() {
282     return getStyleProperty; 282     return getStyleProperty;
283   }); 283   });
284 } else if ( typeof exports === 'object' ) { 284 } else if ( typeof exports === 'object' ) {
285   // CommonJS for Component 285   // CommonJS for Component
286   module.exports = getStyleProperty; 286   module.exports = getStyleProperty;
287 } else { 287 } else {
288   // browser global 288   // browser global
289   window.getStyleProperty = getStyleProperty; 289   window.getStyleProperty = getStyleProperty;
290 } 290 }
291  291 
292 })( window ); 292 })( window );
293  293 
294 /*! 294 /*!
295  * getSize v1.2.2 295  * getSize v1.2.2
296  * measure size of elements 296  * measure size of elements
297  * MIT license 297  * MIT license
298  */ 298  */
299  299 
300 /*jshint browser: true, strict: true, undef: true, unused: true */ 300 /*jshint browser: true, strict: true, undef: true, unused: true */
301 /*global define: false, exports: false, require: false, module: false, console: false */ 301 /*global define: false, exports: false, require: false, module: false, console: false */
302  302 
303 ( function( window, undefined ) { 303 ( function( window, undefined ) {
304  304 
305  305 
306  306 
307 // -------------------------- helpers -------------------------- // 307 // -------------------------- helpers -------------------------- //
308  308 
309 // get a number from a string, not a percentage 309 // get a number from a string, not a percentage
310 function getStyleSize( value ) { 310 function getStyleSize( value ) {
311   var num = parseFloat( value ); 311   var num = parseFloat( value );
312   // not a percent like '100%', and a number 312   // not a percent like '100%', and a number
313   var isValid = value.indexOf('%') === -1 && !isNaN( num ); 313   var isValid = value.indexOf('%') === -1 && !isNaN( num );
314   return isValid && num; 314   return isValid && num;
315 } 315 }
316  316 
317 function noop() {} 317 function noop() {}
318  318 
319 var logError = typeof console === 'undefined' ? noop : 319 var logError = typeof console === 'undefined' ? noop :
320   function( message ) { 320   function( message ) {
321     console.error( message ); 321     console.error( message );
322   }; 322   };
323  323 
324 // -------------------------- measurements -------------------------- // 324 // -------------------------- measurements -------------------------- //
325  325 
326 var measurements = [ 326 var measurements = [
327   'paddingLeft', 327   'paddingLeft',
328   'paddingRight', 328   'paddingRight',
329   'paddingTop', 329   'paddingTop',
330   'paddingBottom', 330   'paddingBottom',
331   'marginLeft', 331   'marginLeft',
332   'marginRight', 332   'marginRight',
333   'marginTop', 333   'marginTop',
334   'marginBottom', 334   'marginBottom',
335   'borderLeftWidth', 335   'borderLeftWidth',
336   'borderRightWidth', 336   'borderRightWidth',
337   'borderTopWidth', 337   'borderTopWidth',
338   'borderBottomWidth' 338   'borderBottomWidth'
339 ]; 339 ];
340  340 
341 function getZeroSize() { 341 function getZeroSize() {
342   var size = { 342   var size = {
343     width: 0, 343     width: 0,
344     height: 0, 344     height: 0,
345     innerWidth: 0, 345     innerWidth: 0,
346     innerHeight: 0, 346     innerHeight: 0,
347     outerWidth: 0, 347     outerWidth: 0,
348     outerHeight: 0 348     outerHeight: 0
349   }; 349   };
350   for ( var i=0, len = measurements.length; i < len; i++ ) { 350   for ( var i=0, len = measurements.length; i < len; i++ ) {
351     var measurement = measurements[i]; 351     var measurement = measurements[i];
352     size[ measurement ] = 0; 352     size[ measurement ] = 0;
353   } 353   }
354   return size; 354   return size;
355 } 355 }
356  356 
357  357 
358  358 
359 function defineGetSize( getStyleProperty ) { 359 function defineGetSize( getStyleProperty ) {
360  360 
361 // -------------------------- setup -------------------------- // 361 // -------------------------- setup -------------------------- //
362  362 
363 var isSetup = false; 363 var isSetup = false;
364  364 
365 var getStyle, boxSizingProp, isBoxSizeOuter; 365 var getStyle, boxSizingProp, isBoxSizeOuter;
366  366 
367 /** 367 /**
368  * setup vars and functions 368  * setup vars and functions
369  * do it on initial getSize(), rather than on script load 369  * do it on initial getSize(), rather than on script load
370  * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397 370  * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397
371  */ 371  */
372 function setup() { 372 function setup() {
373   // setup once 373   // setup once
374   if ( isSetup ) { 374   if ( isSetup ) {
375     return; 375     return;
376   } 376   }
377   isSetup = true; 377   isSetup = true;
378  378 
379   var getComputedStyle = window.getComputedStyle; 379   var getComputedStyle = window.getComputedStyle;
380   getStyle = ( function() { 380   getStyle = ( function() {
381     var getStyleFn = getComputedStyle ? 381     var getStyleFn = getComputedStyle ?
382       function( elem ) { 382       function( elem ) {
383         return getComputedStyle( elem, null ); 383         return getComputedStyle( elem, null );
384       } : 384       } :
385       function( elem ) { 385       function( elem ) {
386         return elem.currentStyle; 386         return elem.currentStyle;
387       }; 387       };
388  388 
389       return function getStyle( elem ) { 389       return function getStyle( elem ) {
390         var style = getStyleFn( elem ); 390         var style = getStyleFn( elem );
391         if ( !style ) { 391         if ( !style ) {
392           logError( 'Style returned ' + style + 392           logError( 'Style returned ' + style +
393             '. Are you running this code in a hidden iframe on Firefox? ' + 393             '. Are you running this code in a hidden iframe on Firefox? ' +
394             'See http://bit.ly/getsizebug1' ); 394             'See http://bit.ly/getsizebug1' );
395         } 395         }
396         return style; 396         return style;
397       }; 397       };
398   })(); 398   })();
399  399 
400   // -------------------------- box sizing -------------------------- // 400   // -------------------------- box sizing -------------------------- //
401  401 
402   boxSizingProp = getStyleProperty('boxSizing'); 402   boxSizingProp = getStyleProperty('boxSizing');
403  403 
404   /** 404   /**
405    * WebKit measures the outer-width on style.width on border-box elems 405    * WebKit measures the outer-width on style.width on border-box elems
406    * IE & Firefox measures the inner-width 406    * IE & Firefox measures the inner-width
407    */ 407    */
408   if ( boxSizingProp ) { 408   if ( boxSizingProp ) {
409     var div = document.createElement('div'); 409     var div = document.createElement('div');
410     div.style.width = '200px'; 410     div.style.width = '200px';
411     div.style.padding = '1px 2px 3px 4px'; 411     div.style.padding = '1px 2px 3px 4px';
412     div.style.borderStyle = 'solid'; 412     div.style.borderStyle = 'solid';
413     div.style.borderWidth = '1px 2px 3px 4px'; 413     div.style.borderWidth = '1px 2px 3px 4px';
414     div.style[ boxSizingProp ] = 'border-box'; 414     div.style[ boxSizingProp ] = 'border-box';
415  415 
416     var body = document.body || document.documentElement; 416     var body = document.body || document.documentElement;
417     body.appendChild( div ); 417     body.appendChild( div );
418     var style = getStyle( div ); 418     var style = getStyle( div );
419  419 
420     isBoxSizeOuter = getStyleSize( style.width ) === 200; 420     isBoxSizeOuter = getStyleSize( style.width ) === 200;
421     body.removeChild( div ); 421     body.removeChild( div );
422   } 422   }
423  423 
424 } 424 }
425  425 
426 // -------------------------- getSize -------------------------- // 426 // -------------------------- getSize -------------------------- //
427  427 
428 function getSize( elem ) { 428 function getSize( elem ) {
429   setup(); 429   setup();
430  430 
431   // use querySeletor if elem is string 431   // use querySeletor if elem is string
432   if ( typeof elem === 'string' ) { 432   if ( typeof elem === 'string' ) {
433     elem = document.querySelector( elem ); 433     elem = document.querySelector( elem );
434   } 434   }
435  435 
436   // do not proceed on non-objects 436   // do not proceed on non-objects
437   if ( !elem || typeof elem !== 'object' || !elem.nodeType ) { 437   if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
438     return; 438     return;
439   } 439   }
440  440 
441   var style = getStyle( elem ); 441   var style = getStyle( elem );
442  442 
443   // if hidden, everything is 0 443   // if hidden, everything is 0
444   if ( style.display === 'none' ) { 444   if ( style.display === 'none' ) {
445     return getZeroSize(); 445     return getZeroSize();
446   } 446   }
447  447 
448   var size = {}; 448   var size = {};
449   size.width = elem.offsetWidth; 449   size.width = elem.offsetWidth;
450   size.height = elem.offsetHeight; 450   size.height = elem.offsetHeight;
451  451 
452   var isBorderBox = size.isBorderBox = !!( boxSizingProp && 452   var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
453     style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' ); 453     style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
454  454 
455   // get all measurements 455   // get all measurements
456   for ( var i=0, len = measurements.length; i < len; i++ ) { 456   for ( var i=0, len = measurements.length; i < len; i++ ) {
457     var measurement = measurements[i]; 457     var measurement = measurements[i];
458     var value = style[ measurement ]; 458     var value = style[ measurement ];
459     value = mungeNonPixel( elem, value ); 459     value = mungeNonPixel( elem, value );
460     var num = parseFloat( value ); 460     var num = parseFloat( value );
461     // any 'auto', 'medium' value will be 0 461     // any 'auto', 'medium' value will be 0
462     size[ measurement ] = !isNaN( num ) ? num : 0; 462     size[ measurement ] = !isNaN( num ) ? num : 0;
463   } 463   }
464  464 
465   var paddingWidth = size.paddingLeft + size.paddingRight; 465   var paddingWidth = size.paddingLeft + size.paddingRight;
466   var paddingHeight = size.paddingTop + size.paddingBottom; 466   var paddingHeight = size.paddingTop + size.paddingBottom;
467   var marginWidth = size.marginLeft + size.marginRight; 467   var marginWidth = size.marginLeft + size.marginRight;
468   var marginHeight = size.marginTop + size.marginBottom; 468   var marginHeight = size.marginTop + size.marginBottom;
469   var borderWidth = size.borderLeftWidth + size.borderRightWidth; 469   var borderWidth = size.borderLeftWidth + size.borderRightWidth;
470   var borderHeight = size.borderTopWidth + size.borderBottomWidth; 470   var borderHeight = size.borderTopWidth + size.borderBottomWidth;
471  471 
472   var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; 472   var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
473  473 
474   // overwrite width and height if we can get it from style 474   // overwrite width and height if we can get it from style
475   var styleWidth = getStyleSize( style.width ); 475   var styleWidth = getStyleSize( style.width );
476   if ( styleWidth !== false ) { 476   if ( styleWidth !== false ) {
477     size.width = styleWidth + 477     size.width = styleWidth +
478       // add padding and border unless it's already including it 478       // add padding and border unless it's already including it
479       ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); 479       ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
480   } 480   }
481  481 
482   var styleHeight = getStyleSize( style.height ); 482   var styleHeight = getStyleSize( style.height );
483   if ( styleHeight !== false ) { 483   if ( styleHeight !== false ) {
484     size.height = styleHeight + 484     size.height = styleHeight +
485       // add padding and border unless it's already including it 485       // add padding and border unless it's already including it
486       ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); 486       ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
487   } 487   }
488  488 
489   size.innerWidth = size.width - ( paddingWidth + borderWidth ); 489   size.innerWidth = size.width - ( paddingWidth + borderWidth );
490   size.innerHeight = size.height - ( paddingHeight + borderHeight ); 490   size.innerHeight = size.height - ( paddingHeight + borderHeight );
491  491 
492   size.outerWidth = size.width + marginWidth; 492   size.outerWidth = size.width + marginWidth;
493   size.outerHeight = size.height + marginHeight; 493   size.outerHeight = size.height + marginHeight;
494  494 
495   return size; 495   return size;
496 } 496 }
497  497 
498 // IE8 returns percent values, not pixels 498 // IE8 returns percent values, not pixels
499 // taken from jQuery's curCSS 499 // taken from jQuery's curCSS
500 function mungeNonPixel( elem, value ) { 500 function mungeNonPixel( elem, value ) {
501   // IE8 and has percent value 501   // IE8 and has percent value
502   if ( window.getComputedStyle || value.indexOf('%') === -1 ) { 502   if ( window.getComputedStyle || value.indexOf('%') === -1 ) {
503     return value; 503     return value;
504   } 504   }
505   var style = elem.style; 505   var style = elem.style;
506   // Remember the original values 506   // Remember the original values
507   var left = style.left; 507   var left = style.left;
508   var rs = elem.runtimeStyle; 508   var rs = elem.runtimeStyle;
509   var rsLeft = rs && rs.left; 509   var rsLeft = rs && rs.left;
510  510 
511   // Put in the new values to get a computed value out 511   // Put in the new values to get a computed value out
512   if ( rsLeft ) { 512   if ( rsLeft ) {
513     rs.left = elem.currentStyle.left; 513     rs.left = elem.currentStyle.left;
514   } 514   }
515   style.left = value; 515   style.left = value;
516   value = style.pixelLeft; 516   value = style.pixelLeft;
517  517 
518   // Revert the changed values 518   // Revert the changed values
519   style.left = left; 519   style.left = left;
520   if ( rsLeft ) { 520   if ( rsLeft ) {
521     rs.left = rsLeft; 521     rs.left = rsLeft;
522   } 522   }
523  523 
524   return value; 524   return value;
525 } 525 }
526  526 
527 return getSize; 527 return getSize;
528  528 
529 } 529 }
530  530 
531 // transport 531 // transport
532 if ( typeof define === 'function' && define.amd ) { 532 if ( typeof define === 'function' && define.amd ) {
533   // AMD for RequireJS 533   // AMD for RequireJS
534   define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize ); 534   define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize );
535 } else if ( typeof exports === 'object' ) { 535 } else if ( typeof exports === 'object' ) {
536   // CommonJS for Component 536   // CommonJS for Component
537   module.exports = defineGetSize( require('desandro-get-style-property') ); 537   module.exports = defineGetSize( require('desandro-get-style-property') );
538 } else { 538 } else {
539   // browser global 539   // browser global
540   window.getSize = defineGetSize( window.getStyleProperty ); 540   window.getSize = defineGetSize( window.getStyleProperty );
541 } 541 }
542  542 
543 })( window ); 543 })( window );
544  544 
545 /*! 545 /*!
546  * eventie v1.0.6 546  * eventie v1.0.6
547  * event binding helper 547  * event binding helper
548  *   eventie.bind( elem, 'click', myFn ) 548  *   eventie.bind( elem, 'click', myFn )
549  *   eventie.unbind( elem, 'click', myFn ) 549  *   eventie.unbind( elem, 'click', myFn )
550  * MIT license 550  * MIT license
551  */ 551  */
552  552 
553 /*jshint browser: true, undef: true, unused: true */ 553 /*jshint browser: true, undef: true, unused: true */
554 /*global define: false, module: false */ 554 /*global define: false, module: false */
555  555 
556 ( function( window ) { 556 ( function( window ) {
557  557 
558  558 
559  559 
560 var docElem = document.documentElement; 560 var docElem = document.documentElement;
561  561 
562 var bind = function() {}; 562 var bind = function() {};
563  563 
564 function getIEEvent( obj ) { 564 function getIEEvent( obj ) {
565   var event = window.event; 565   var event = window.event;
566   // add event.target 566   // add event.target
567   event.target = event.target || event.srcElement || obj; 567   event.target = event.target || event.srcElement || obj;
568   return event; 568   return event;
569 } 569 }
570  570 
571 if ( docElem.addEventListener ) { 571 if ( docElem.addEventListener ) {
572   bind = function( obj, type, fn ) { 572   bind = function( obj, type, fn ) {
573     obj.addEventListener( type, fn, false ); 573     obj.addEventListener( type, fn, false );
574   }; 574   };
575 } else if ( docElem.attachEvent ) { 575 } else if ( docElem.attachEvent ) {
576   bind = function( obj, type, fn ) { 576   bind = function( obj, type, fn ) {
577     obj[ type + fn ] = fn.handleEvent ? 577     obj[ type + fn ] = fn.handleEvent ?
578       function() { 578       function() {
579         var event = getIEEvent( obj ); 579         var event = getIEEvent( obj );
580         fn.handleEvent.call( fn, event ); 580         fn.handleEvent.call( fn, event );
581       } : 581       } :
582       function() { 582       function() {
583         var event = getIEEvent( obj ); 583         var event = getIEEvent( obj );
584         fn.call( obj, event ); 584         fn.call( obj, event );
585       }; 585       };
586     obj.attachEvent( "on" + type, obj[ type + fn ] ); 586     obj.attachEvent( "on" + type, obj[ type + fn ] );
587   }; 587   };
588 } 588 }
589  589 
590 var unbind = function() {}; 590 var unbind = function() {};
591  591 
592 if ( docElem.removeEventListener ) { 592 if ( docElem.removeEventListener ) {
593   unbind = function( obj, type, fn ) { 593   unbind = function( obj, type, fn ) {
594     obj.removeEventListener( type, fn, false ); 594     obj.removeEventListener( type, fn, false );
595   }; 595   };
596 } else if ( docElem.detachEvent ) { 596 } else if ( docElem.detachEvent ) {
597   unbind = function( obj, type, fn ) { 597   unbind = function( obj, type, fn ) {
598     obj.detachEvent( "on" + type, obj[ type + fn ] ); 598     obj.detachEvent( "on" + type, obj[ type + fn ] );
599     try { 599     try {
600       delete obj[ type + fn ]; 600       delete obj[ type + fn ];
601     } catch ( err ) { 601     } catch ( err ) {
602       // can't delete window object properties 602       // can't delete window object properties
603       obj[ type + fn ] = undefined; 603       obj[ type + fn ] = undefined;
604     } 604     }
605   }; 605   };
606 } 606 }
607  607 
608 var eventie = { 608 var eventie = {
609   bind: bind, 609   bind: bind,
610   unbind: unbind 610   unbind: unbind
611 }; 611 };
612  612 
613 // ----- module definition ----- // 613 // ----- module definition ----- //
614  614 
615 if ( typeof define === 'function' && define.amd ) { 615 if ( typeof define === 'function' && define.amd ) {
616   // AMD 616   // AMD
617   define( 'eventie/eventie',eventie ); 617   define( 'eventie/eventie',eventie );
618 } else if ( typeof exports === 'object' ) { 618 } else if ( typeof exports === 'object' ) {
619   // CommonJS 619   // CommonJS
620   module.exports = eventie; 620   module.exports = eventie;
621 } else { 621 } else {
622   // browser global 622   // browser global
623   window.eventie = eventie; 623   window.eventie = eventie;
624 } 624 }
625 window.eventie = eventie; 625 window.eventie = eventie;
626 })( window ); 626 })( window );
627  627 
628 /*! 628 /*!
629  * EventEmitter v4.2.11 - git.io/ee 629  * EventEmitter v4.2.11 - git.io/ee
630  * Unlicense - http://unlicense.org/ 630  * Unlicense - http://unlicense.org/
631  * Oliver Caldwell - http://oli.me.uk/ 631  * Oliver Caldwell - http://oli.me.uk/
632  * @preserve 632  * @preserve
633  */ 633  */
634  634 
635 ;(function () { 635 ;(function () {
636      636     
637  637 
638     /** 638     /**
639      * Class for managing events. 639      * Class for managing events.
640      * Can be extended to provide event functionality in other classes. 640      * Can be extended to provide event functionality in other classes.
641      * 641      *
642      * @class EventEmitter Manages event registering and emitting. 642      * @class EventEmitter Manages event registering and emitting.
643      */ 643      */
644     function EventEmitter() {} 644     function EventEmitter() {}
645  645 
646     // Shortcuts to improve speed and size 646     // Shortcuts to improve speed and size
647     var proto = EventEmitter.prototype; 647     var proto = EventEmitter.prototype;
648     var exports = this; 648     var exports = this;
649     var originalGlobalValue = exports.EventEmitter; 649     var originalGlobalValue = exports.EventEmitter;
650  650 
651     /** 651     /**
652      * Finds the index of the listener for the event in its storage array. 652      * Finds the index of the listener for the event in its storage array.
653      * 653      *
654      * @param {Function[]} listeners Array of listeners to search through. 654      * @param {Function[]} listeners Array of listeners to search through.
655      * @param {Function} listener Method to look for. 655      * @param {Function} listener Method to look for.
656      * @return {Number} Index of the specified listener, -1 if not found 656      * @return {Number} Index of the specified listener, -1 if not found
657      * @api private 657      * @api private
658      */ 658      */
659     function indexOfListener(listeners, listener) { 659     function indexOfListener(listeners, listener) {
660         var i = listeners.length; 660         var i = listeners.length;
661         while (i--) { 661         while (i--) {
662             if (listeners[i].listener === listener) { 662             if (listeners[i].listener === listener) {
663                 return i; 663                 return i;
664             } 664             }
665         } 665         }
666  666 
667         return -1; 667         return -1;
668     } 668     }
669  669 
670     /** 670     /**
671      * Alias a method while keeping the context correct, to allow for overwriting of target method. 671      * Alias a method while keeping the context correct, to allow for overwriting of target method.
672      * 672      *
673      * @param {String} name The name of the target method. 673      * @param {String} name The name of the target method.
674      * @return {Function} The aliased method 674      * @return {Function} The aliased method
675      * @api private 675      * @api private
676      */ 676      */
677     function alias(name) { 677     function alias(name) {
678         return function aliasClosure() { 678         return function aliasClosure() {
679             return this[name].apply(this, arguments); 679             return this[name].apply(this, arguments);
680         }; 680         };
681     } 681     }
682  682 
683     /** 683     /**
684      * Returns the listener array for the specified event. 684      * Returns the listener array for the specified event.
685      * Will initialise the event object and listener arrays if required. 685      * Will initialise the event object and listener arrays if required.
686      * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. 686      * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
687      * Each property in the object response is an array of listener functions. 687      * Each property in the object response is an array of listener functions.
688      * 688      *
689      * @param {String|RegExp} evt Name of the event to return the listeners from. 689      * @param {String|RegExp} evt Name of the event to return the listeners from.
690      * @return {Function[]|Object} All listener functions for the event. 690      * @return {Function[]|Object} All listener functions for the event.
691      */ 691      */
692     proto.getListeners = function getListeners(evt) { 692     proto.getListeners = function getListeners(evt) {
693         var events = this._getEvents(); 693         var events = this._getEvents();
694         var response; 694         var response;
695         var key; 695         var key;
696  696 
697         // Return a concatenated array of all matching events if 697         // Return a concatenated array of all matching events if
698         // the selector is a regular expression. 698         // the selector is a regular expression.
699         if (evt instanceof RegExp) { 699         if (evt instanceof RegExp) {
700             response = {}; 700             response = {};
701             for (key in events) { 701             for (key in events) {
702                 if (events.hasOwnProperty(key) && evt.test(key)) { 702                 if (events.hasOwnProperty(key) && evt.test(key)) {
703                     response[key] = events[key]; 703                     response[key] = events[key];
704                 } 704                 }
705             } 705             }
706         } 706         }
707         else { 707         else {
708             response = events[evt] || (events[evt] = []); 708             response = events[evt] || (events[evt] = []);
709         } 709         }
710  710 
711         return response; 711         return response;
712     }; 712     };
713  713 
714     /** 714     /**
715      * Takes a list of listener objects and flattens it into a list of listener functions. 715      * Takes a list of listener objects and flattens it into a list of listener functions.
716      * 716      *
717      * @param {Object[]} listeners Raw listener objects. 717      * @param {Object[]} listeners Raw listener objects.
718      * @return {Function[]} Just the listener functions. 718      * @return {Function[]} Just the listener functions.
719      */ 719      */
720     proto.flattenListeners = function flattenListeners(listeners) { 720     proto.flattenListeners = function flattenListeners(listeners) {
721         var flatListeners = []; 721         var flatListeners = [];
722         var i; 722         var i;
723  723 
724         for (i = 0; i < listeners.length; i += 1) { 724         for (i = 0; i < listeners.length; i += 1) {
725             flatListeners.push(listeners[i].listener); 725             flatListeners.push(listeners[i].listener);
726         } 726         }
727  727 
728         return flatListeners; 728         return flatListeners;
729     }; 729     };
730  730 
731     /** 731     /**
732      * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful. 732      * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
733      * 733      *
734      * @param {String|RegExp} evt Name of the event to return the listeners from. 734      * @param {String|RegExp} evt Name of the event to return the listeners from.
735      * @return {Object} All listener functions for an event in an object. 735      * @return {Object} All listener functions for an event in an object.
736      */ 736      */
737     proto.getListenersAsObject = function getListenersAsObject(evt) { 737     proto.getListenersAsObject = function getListenersAsObject(evt) {
738         var listeners = this.getListeners(evt); 738         var listeners = this.getListeners(evt);
739         var response; 739         var response;
740  740 
741         if (listeners instanceof Array) { 741         if (listeners instanceof Array) {
742             response = {}; 742             response = {};
743             response[evt] = listeners; 743             response[evt] = listeners;
744         } 744         }
745  745 
746         return response || listeners; 746         return response || listeners;
747     }; 747     };
748  748 
749     /** 749     /**
750      * Adds a listener function to the specified event. 750      * Adds a listener function to the specified event.
751      * The listener will not be added if it is a duplicate. 751      * The listener will not be added if it is a duplicate.
752      * If the listener returns true then it will be removed after it is called. 752      * If the listener returns true then it will be removed after it is called.
753      * If you pass a regular expression as the event name then the listener will be added to all events that match it. 753      * If you pass a regular expression as the event name then the listener will be added to all events that match it.
754      * 754      *
755      * @param {String|RegExp} evt Name of the event to attach the listener to. 755      * @param {String|RegExp} evt Name of the event to attach the listener to.
756      * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 756      * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
757      * @return {Object} Current instance of EventEmitter for chaining. 757      * @return {Object} Current instance of EventEmitter for chaining.
758      */ 758      */
759     proto.addListener = function addListener(evt, listener) { 759     proto.addListener = function addListener(evt, listener) {
760         var listeners = this.getListenersAsObject(evt); 760         var listeners = this.getListenersAsObject(evt);
761         var listenerIsWrapped = typeof listener === 'object'; 761         var listenerIsWrapped = typeof listener === 'object';
762         var key; 762         var key;
763  763 
764         for (key in listeners) { 764         for (key in listeners) {
765             if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { 765             if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
766                 listeners[key].push(listenerIsWrapped ? listener : { 766                 listeners[key].push(listenerIsWrapped ? listener : {
767                     listener: listener, 767                     listener: listener,
768                     once: false 768                     once: false
769                 }); 769                 });
770             } 770             }
771         } 771         }
772  772 
773         return this; 773         return this;
774     }; 774     };
775  775 
776     /** 776     /**
777      * Alias of addListener 777      * Alias of addListener
778      */ 778      */
779     proto.on = alias('addListener'); 779     proto.on = alias('addListener');
780  780 
781     /** 781     /**
782      * Semi-alias of addListener. It will add a listener that will be 782      * Semi-alias of addListener. It will add a listener that will be
783      * automatically removed after its first execution. 783      * automatically removed after its first execution.
784      * 784      *
785      * @param {String|RegExp} evt Name of the event to attach the listener to. 785      * @param {String|RegExp} evt Name of the event to attach the listener to.
786      * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 786      * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
787      * @return {Object} Current instance of EventEmitter for chaining. 787      * @return {Object} Current instance of EventEmitter for chaining.
788      */ 788      */
789     proto.addOnceListener = function addOnceListener(evt, listener) { 789     proto.addOnceListener = function addOnceListener(evt, listener) {
790         return this.addListener(evt, { 790         return this.addListener(evt, {
791             listener: listener, 791             listener: listener,
792             once: true 792             once: true
793         }); 793         });
794     }; 794     };
795  795 
796     /** 796     /**
797      * Alias of addOnceListener. 797      * Alias of addOnceListener.
798      */ 798      */
799     proto.once = alias('addOnceListener'); 799     proto.once = alias('addOnceListener');
800  800 
801     /** 801     /**
802      * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad. 802      * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
803      * You need to tell it what event names should be matched by a regex. 803      * You need to tell it what event names should be matched by a regex.
804      * 804      *
805      * @param {String} evt Name of the event to create. 805      * @param {String} evt Name of the event to create.
806      * @return {Object} Current instance of EventEmitter for chaining. 806      * @return {Object} Current instance of EventEmitter for chaining.
807      */ 807      */
808     proto.defineEvent = function defineEvent(evt) { 808     proto.defineEvent = function defineEvent(evt) {
809         this.getListeners(evt); 809         this.getListeners(evt);
810         return this; 810         return this;
811     }; 811     };
812  812 
813     /** 813     /**
814      * Uses defineEvent to define multiple events. 814      * Uses defineEvent to define multiple events.
815      * 815      *
816      * @param {String[]} evts An array of event names to define. 816      * @param {String[]} evts An array of event names to define.
817      * @return {Object} Current instance of EventEmitter for chaining. 817      * @return {Object} Current instance of EventEmitter for chaining.
818      */ 818      */
819     proto.defineEvents = function defineEvents(evts) { 819     proto.defineEvents = function defineEvents(evts) {
820         for (var i = 0; i < evts.length; i += 1) { 820         for (var i = 0; i < evts.length; i += 1) {
821             this.defineEvent(evts[i]); 821             this.defineEvent(evts[i]);
822         } 822         }
823         return this; 823         return this;
824     }; 824     };
825  825 
826     /** 826     /**
827      * Removes a listener function from the specified event. 827      * Removes a listener function from the specified event.
828      * When passed a regular expression as the event name, it will remove the listener from all events that match it. 828      * When passed a regular expression as the event name, it will remove the listener from all events that match it.
829      * 829      *
830      * @param {String|RegExp} evt Name of the event to remove the listener from. 830      * @param {String|RegExp} evt Name of the event to remove the listener from.
831      * @param {Function} listener Method to remove from the event. 831      * @param {Function} listener Method to remove from the event.
832      * @return {Object} Current instance of EventEmitter for chaining. 832      * @return {Object} Current instance of EventEmitter for chaining.
833      */ 833      */
834     proto.removeListener = function removeListener(evt, listener) { 834     proto.removeListener = function removeListener(evt, listener) {
835         var listeners = this.getListenersAsObject(evt); 835         var listeners = this.getListenersAsObject(evt);
836         var index; 836         var index;
837         var key; 837         var key;
838  838 
839         for (key in listeners) { 839         for (key in listeners) {
840             if (listeners.hasOwnProperty(key)) { 840             if (listeners.hasOwnProperty(key)) {
841                 index = indexOfListener(listeners[key], listener); 841                 index = indexOfListener(listeners[key], listener);
842  842 
843                 if (index !== -1) { 843                 if (index !== -1) {
844                     listeners[key].splice(index, 1); 844                     listeners[key].splice(index, 1);
845                 } 845                 }
846             } 846             }
847         } 847         }
848  848 
849         return this; 849         return this;
850     }; 850     };
851  851 
852     /** 852     /**
853      * Alias of removeListener 853      * Alias of removeListener
854      */ 854      */
855     proto.off = alias('removeListener'); 855     proto.off = alias('removeListener');
856  856 
857     /** 857     /**
858      * Adds listeners in bulk using the manipulateListeners method. 858      * Adds listeners in bulk using the manipulateListeners method.
859      * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added. 859      * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
860      * You can also pass it a regular expression to add the array of listeners to all events that match it. 860      * You can also pass it a regular expression to add the array of listeners to all events that match it.
861      * Yeah, this function does quite a bit. That's probably a bad thing. 861      * Yeah, this function does quite a bit. That's probably a bad thing.
862      * 862      *
863      * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once. 863      * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
864      * @param {Function[]} [listeners] An optional array of listener functions to add. 864      * @param {Function[]} [listeners] An optional array of listener functions to add.
865      * @return {Object} Current instance of EventEmitter for chaining. 865      * @return {Object} Current instance of EventEmitter for chaining.
866      */ 866      */
867     proto.addListeners = function addListeners(evt, listeners) { 867     proto.addListeners = function addListeners(evt, listeners) {
868         // Pass through to manipulateListeners 868         // Pass through to manipulateListeners
869         return this.manipulateListeners(false, evt, listeners); 869         return this.manipulateListeners(false, evt, listeners);
870     }; 870     };
871  871 
872     /** 872     /**
873      * Removes listeners in bulk using the manipulateListeners method. 873      * Removes listeners in bulk using the manipulateListeners method.
874      * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 874      * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
875      * You can also pass it an event name and an array of listeners to be removed. 875      * You can also pass it an event name and an array of listeners to be removed.
876      * You can also pass it a regular expression to remove the listeners from all events that match it. 876      * You can also pass it a regular expression to remove the listeners from all events that match it.
877      * 877      *
878      * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once. 878      * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
879      * @param {Function[]} [listeners] An optional array of listener functions to remove. 879      * @param {Function[]} [listeners] An optional array of listener functions to remove.
880      * @return {Object} Current instance of EventEmitter for chaining. 880      * @return {Object} Current instance of EventEmitter for chaining.
881      */ 881      */
882     proto.removeListeners = function removeListeners(evt, listeners) { 882     proto.removeListeners = function removeListeners(evt, listeners) {
883         // Pass through to manipulateListeners 883         // Pass through to manipulateListeners
884         return this.manipulateListeners(true, evt, listeners); 884         return this.manipulateListeners(true, evt, listeners);
885     }; 885     };
886  886 
887     /** 887     /**
888      * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level. 888      * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
889      * The first argument will determine if the listeners are removed (true) or added (false). 889      * The first argument will determine if the listeners are removed (true) or added (false).
890      * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 890      * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
891      * You can also pass it an event name and an array of listeners to be added/removed. 891      * You can also pass it an event name and an array of listeners to be added/removed.
892      * You can also pass it a regular expression to manipulate the listeners of all events that match it. 892      * You can also pass it a regular expression to manipulate the listeners of all events that match it.
893      * 893      *
894      * @param {Boolean} remove True if you want to remove listeners, false if you want to add. 894      * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
895      * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once. 895      * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
896      * @param {Function[]} [listeners] An optional array of listener functions to add/remove. 896      * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
897      * @return {Object} Current instance of EventEmitter for chaining. 897      * @return {Object} Current instance of EventEmitter for chaining.
898      */ 898      */
899     proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { 899     proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
900         var i; 900         var i;
901         var value; 901         var value;
902         var single = remove ? this.removeListener : this.addListener; 902         var single = remove ? this.removeListener : this.addListener;
903         var multiple = remove ? this.removeListeners : this.addListeners; 903         var multiple = remove ? this.removeListeners : this.addListeners;
904  904 
905         // If evt is an object then pass each of its properties to this method 905         // If evt is an object then pass each of its properties to this method
906         if (typeof evt === 'object' && !(evt instanceof RegExp)) { 906         if (typeof evt === 'object' && !(evt instanceof RegExp)) {
907             for (i in evt) { 907             for (i in evt) {
908                 if (evt.hasOwnProperty(i) && (value = evt[i])) { 908                 if (evt.hasOwnProperty(i) && (value = evt[i])) {
909                     // Pass the single listener straight through to the singular method 909                     // Pass the single listener straight through to the singular method
910                     if (typeof value === 'function') { 910                     if (typeof value === 'function') {
911                         single.call(this, i, value); 911                         single.call(this, i, value);
912                     } 912                     }
913                     else { 913                     else {
914                         // Otherwise pass back to the multiple function 914                         // Otherwise pass back to the multiple function
915                         multiple.call(this, i, value); 915                         multiple.call(this, i, value);
916                     } 916                     }
917                 } 917                 }
918             } 918             }
919         } 919         }
920         else { 920         else {
921             // So evt must be a string 921             // So evt must be a string
922             // And listeners must be an array of listeners 922             // And listeners must be an array of listeners
923             // Loop over it and pass each one to the multiple method 923             // Loop over it and pass each one to the multiple method
924             i = listeners.length; 924             i = listeners.length;
925             while (i--) { 925             while (i--) {
926                 single.call(this, evt, listeners[i]); 926                 single.call(this, evt, listeners[i]);
927             } 927             }
928         } 928         }
929  929 
930         return this; 930         return this;
931     }; 931     };
932  932 
933     /** 933     /**
934      * Removes all listeners from a specified event. 934      * Removes all listeners from a specified event.
935      * If you do not specify an event then all listeners will be removed. 935      * If you do not specify an event then all listeners will be removed.
936      * That means every event will be emptied. 936      * That means every event will be emptied.
937      * You can also pass a regex to remove all events that match it. 937      * You can also pass a regex to remove all events that match it.
938      * 938      *
939      * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. 939      * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
940      * @return {Object} Current instance of EventEmitter for chaining. 940      * @return {Object} Current instance of EventEmitter for chaining.
941      */ 941      */
942     proto.removeEvent = function removeEvent(evt) { 942     proto.removeEvent = function removeEvent(evt) {
943         var type = typeof evt; 943         var type = typeof evt;
944         var events = this._getEvents(); 944         var events = this._getEvents();
945         var key; 945         var key;
946  946 
947         // Remove different things depending on the state of evt 947         // Remove different things depending on the state of evt
948         if (type === 'string') { 948         if (type === 'string') {
949             // Remove all listeners for the specified event 949             // Remove all listeners for the specified event
950             delete events[evt]; 950             delete events[evt];
951         } 951         }
952         else if (evt instanceof RegExp) { 952         else if (evt instanceof RegExp) {
953             // Remove all events matching the regex. 953             // Remove all events matching the regex.
954             for (key in events) { 954             for (key in events) {
955                 if (events.hasOwnProperty(key) && evt.test(key)) { 955                 if (events.hasOwnProperty(key) && evt.test(key)) {
956                     delete events[key]; 956                     delete events[key];
957                 } 957                 }
958             } 958             }
959         } 959         }
960         else { 960         else {
961             // Remove all listeners in all events 961             // Remove all listeners in all events
962             delete this._events; 962             delete this._events;
963         } 963         }
964  964 
965         return this; 965         return this;
966     }; 966     };
967  967 
968     /** 968     /**
969      * Alias of removeEvent. 969      * Alias of removeEvent.
970      * 970      *
971      * Added to mirror the node API. 971      * Added to mirror the node API.
972      */ 972      */
973     proto.removeAllListeners = alias('removeEvent'); 973     proto.removeAllListeners = alias('removeEvent');
974  974 
975     /** 975     /**
976      * Emits an event of your choice. 976      * Emits an event of your choice.
977      * When emitted, every listener attached to that event will be executed. 977      * When emitted, every listener attached to that event will be executed.
978      * If you pass the optional argument array then those arguments will be passed to every listener upon execution. 978      * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
979      * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately. 979      * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
980      * So they will not arrive within the array on the other side, they will be separate. 980      * So they will not arrive within the array on the other side, they will be separate.
981      * You can also pass a regular expression to emit to all events that match it. 981      * You can also pass a regular expression to emit to all events that match it.
982      * 982      *
983      * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 983      * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
984      * @param {Array} [args] Optional array of arguments to be passed to each listener. 984      * @param {Array} [args] Optional array of arguments to be passed to each listener.
985      * @return {Object} Current instance of EventEmitter for chaining. 985      * @return {Object} Current instance of EventEmitter for chaining.
986      */ 986      */
987     proto.emitEvent = function emitEvent(evt, args) { 987     proto.emitEvent = function emitEvent(evt, args) {
988         var listeners = this.getListenersAsObject(evt); 988         var listeners = this.getListenersAsObject(evt);
989         var listener; 989         var listener;
990         var i; 990         var i;
991         var key; 991         var key;
992         var response; 992         var response;
993  993 
994         for (key in listeners) { 994         for (key in listeners) {
995             if (listeners.hasOwnProperty(key)) { 995             if (listeners.hasOwnProperty(key)) {
996                 i = listeners[key].length; 996                 i = listeners[key].length;
997  997 
998                 while (i--) { 998                 while (i--) {
999                     // If the listener returns true then it shall be removed from the event 999                     // If the listener returns true then it shall be removed from the event
1000                     // The function is executed either with a basic call or an apply if there is an args array 1000                     // The function is executed either with a basic call or an apply if there is an args array
1001                     listener = listeners[key][i]; 1001                     listener = listeners[key][i];
1002  1002 
1003                     if (listener.once === true) { 1003                     if (listener.once === true) {
1004                         this.removeListener(evt, listener.listener); 1004                         this.removeListener(evt, listener.listener);
1005                     } 1005                     }
1006  1006 
1007                     response = listener.listener.apply(this, args || []); 1007                     response = listener.listener.apply(this, args || []);
1008  1008 
1009                     if (response === this._getOnceReturnValue()) { 1009                     if (response === this._getOnceReturnValue()) {
1010                         this.removeListener(evt, listener.listener); 1010                         this.removeListener(evt, listener.listener);
1011                     } 1011                     }
1012                 } 1012                 }
1013             } 1013             }
1014         } 1014         }
1015  1015 
1016         return this; 1016         return this;
1017     }; 1017     };
1018  1018 
1019     /** 1019     /**
1020      * Alias of emitEvent 1020      * Alias of emitEvent
1021      */ 1021      */
1022     proto.trigger = alias('emitEvent'); 1022     proto.trigger = alias('emitEvent');
1023  1023 
1024     /** 1024     /**
1025      * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on. 1025      * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
1026      * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. 1026      * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
1027      * 1027      *
1028      * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 1028      * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
1029      * @param {...*} Optional additional arguments to be passed to each listener. 1029      * @param {...*} Optional additional arguments to be passed to each listener.
1030      * @return {Object} Current instance of EventEmitter for chaining. 1030      * @return {Object} Current instance of EventEmitter for chaining.
1031      */ 1031      */
1032     proto.emit = function emit(evt) { 1032     proto.emit = function emit(evt) {
1033         var args = Array.prototype.slice.call(arguments, 1); 1033         var args = Array.prototype.slice.call(arguments, 1);
1034         return this.emitEvent(evt, args); 1034         return this.emitEvent(evt, args);
1035     }; 1035     };
1036  1036 
1037     /** 1037     /**
1038      * Sets the current value to check against when executing listeners. If a 1038      * Sets the current value to check against when executing listeners. If a
1039      * listeners return value matches the one set here then it will be removed 1039      * listeners return value matches the one set here then it will be removed
1040      * after execution. This value defaults to true. 1040      * after execution. This value defaults to true.
1041      * 1041      *
1042      * @param {*} value The new value to check for when executing listeners. 1042      * @param {*} value The new value to check for when executing listeners.
1043      * @return {Object} Current instance of EventEmitter for chaining. 1043      * @return {Object} Current instance of EventEmitter for chaining.
1044      */ 1044      */
1045     proto.setOnceReturnValue = function setOnceReturnValue(value) { 1045     proto.setOnceReturnValue = function setOnceReturnValue(value) {
1046         this._onceReturnValue = value; 1046         this._onceReturnValue = value;
1047         return this; 1047         return this;
1048     }; 1048     };
1049  1049 
1050     /** 1050     /**
1051      * Fetches the current value to check against when executing listeners. If 1051      * Fetches the current value to check against when executing listeners. If
1052      * the listeners return value matches this one then it should be removed 1052      * the listeners return value matches this one then it should be removed
1053      * automatically. It will return true by default. 1053      * automatically. It will return true by default.
1054      * 1054      *
1055      * @return {*|Boolean} The current value to check for or the default, true. 1055      * @return {*|Boolean} The current value to check for or the default, true.
1056      * @api private 1056      * @api private
1057      */ 1057      */
1058     proto._getOnceReturnValue = function _getOnceReturnValue() { 1058     proto._getOnceReturnValue = function _getOnceReturnValue() {
1059         if (this.hasOwnProperty('_onceReturnValue')) { 1059         if (this.hasOwnProperty('_onceReturnValue')) {
1060             return this._onceReturnValue; 1060             return this._onceReturnValue;
1061         } 1061         }
1062         else { 1062         else {
1063             return true; 1063             return true;
1064         } 1064         }
1065     }; 1065     };
1066  1066 
1067     /** 1067     /**
1068      * Fetches the events object and creates one if required. 1068      * Fetches the events object and creates one if required.
1069      * 1069      *
1070      * @return {Object} The events storage object. 1070      * @return {Object} The events storage object.
1071      * @api private 1071      * @api private
1072      */ 1072      */
1073     proto._getEvents = function _getEvents() { 1073     proto._getEvents = function _getEvents() {
1074         return this._events || (this._events = {}); 1074         return this._events || (this._events = {});
1075     }; 1075     };
1076  1076 
1077     /** 1077     /**
1078      * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version. 1078      * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
1079      * 1079      *
1080      * @return {Function} Non conflicting EventEmitter class. 1080      * @return {Function} Non conflicting EventEmitter class.
1081      */ 1081      */
1082     EventEmitter.noConflict = function noConflict() { 1082     EventEmitter.noConflict = function noConflict() {
1083         exports.EventEmitter = originalGlobalValue; 1083         exports.EventEmitter = originalGlobalValue;
1084         return EventEmitter; 1084         return EventEmitter;
1085     }; 1085     };
1086  1086 
1087     // Expose the class either via AMD, CommonJS or the global object 1087     // Expose the class either via AMD, CommonJS or the global object
1088     if (typeof define === 'function' && define.amd) { 1088     if (typeof define === 'function' && define.amd) {
1089         define('eventEmitter/EventEmitter',[],function () { 1089         define('eventEmitter/EventEmitter',[],function () {
1090             return EventEmitter; 1090             return EventEmitter;
1091         }); 1091         });
1092     } 1092     }
1093     else if (typeof module === 'object' && module.exports){ 1093     else if (typeof module === 'object' && module.exports){
1094         module.exports = EventEmitter; 1094         module.exports = EventEmitter;
1095     } 1095     }
1096     else { 1096     else {
1097         exports.EventEmitter = EventEmitter; 1097         exports.EventEmitter = EventEmitter;
1098     } 1098     }
1099 }.call(this)); 1099 }.call(this));
1100  1100 
1101 /*! 1101 /*!
1102  * docReady v1.0.4 1102  * docReady v1.0.4
1103  * Cross browser DOMContentLoaded event emitter 1103  * Cross browser DOMContentLoaded event emitter
1104  * MIT license 1104  * MIT license
1105  */ 1105  */
1106  1106 
1107 /*jshint browser: true, strict: true, undef: true, unused: true*/ 1107 /*jshint browser: true, strict: true, undef: true, unused: true*/
1108 /*global define: false, require: false, module: false */ 1108 /*global define: false, require: false, module: false */
1109  1109 
1110 ( function( window ) { 1110 ( function( window ) {
1111  1111 
1112  1112 
1113  1113 
1114 var document = window.document; 1114 var document = window.document;
1115 // collection of functions to be triggered on ready 1115 // collection of functions to be triggered on ready
1116 var queue = []; 1116 var queue = [];
1117  1117 
1118 function docReady( fn ) { 1118 function docReady( fn ) {
1119   // throw out non-functions 1119   // throw out non-functions
1120   if ( typeof fn !== 'function' ) { 1120   if ( typeof fn !== 'function' ) {
1121     return; 1121     return;
1122   } 1122   }
1123  1123 
1124   if ( docReady.isReady ) { 1124   if ( docReady.isReady ) {
1125     // ready now, hit it 1125     // ready now, hit it
1126     fn(); 1126     fn();
1127   } else { 1127   } else {
1128     // queue function when ready 1128     // queue function when ready
1129     queue.push( fn ); 1129     queue.push( fn );
1130   } 1130   }
1131 } 1131 }
1132  1132 
1133 docReady.isReady = false; 1133 docReady.isReady = false;
1134  1134 
1135 // triggered on various doc ready events 1135 // triggered on various doc ready events
1136 function onReady( event ) { 1136 function onReady( event ) {
1137   // bail if already triggered or IE8 document is not ready just yet 1137   // bail if already triggered or IE8 document is not ready just yet
1138   var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete'; 1138   var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
1139   if ( docReady.isReady || isIE8NotReady ) { 1139   if ( docReady.isReady || isIE8NotReady ) {
1140     return; 1140     return;
1141   } 1141   }
1142  1142 
1143   trigger(); 1143   trigger();
1144 } 1144 }
1145  1145 
1146 function trigger() { 1146 function trigger() {
1147   docReady.isReady = true; 1147   docReady.isReady = true;
1148   // process queue 1148   // process queue
1149   for ( var i=0, len = queue.length; i < len; i++ ) { 1149   for ( var i=0, len = queue.length; i < len; i++ ) {
1150     var fn = queue[i]; 1150     var fn = queue[i];
1151     fn(); 1151     fn();
1152   } 1152   }
1153 } 1153 }
1154  1154 
1155 function defineDocReady( eventie ) { 1155 function defineDocReady( eventie ) {
1156   // trigger ready if page is ready 1156   // trigger ready if page is ready
1157   if ( document.readyState === 'complete' ) { 1157   if ( document.readyState === 'complete' ) {
1158     trigger(); 1158     trigger();
1159   } else { 1159   } else {
1160     // listen for events 1160     // listen for events
1161     window.eventie.bind( document, 'DOMContentLoaded', onReady ); 1161     window.eventie.bind( document, 'DOMContentLoaded', onReady );
1162     window.eventie.bind( document, 'readystatechange', onReady ); 1162     window.eventie.bind( document, 'readystatechange', onReady );
1163     window.eventie.bind( window, 'load', onReady ); 1163     window.eventie.bind( window, 'load', onReady );
1164   } 1164   }
1165  1165 
1166   return docReady; 1166   return docReady;
1167 } 1167 }
1168  1168 
1169 // transport 1169 // transport
1170 if ( typeof define === 'function' && define.amd ) { 1170 if ( typeof define === 'function' && define.amd ) {
1171   // AMD 1171   // AMD
1172   define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady ); 1172   define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady );
1173 } else if ( typeof exports === 'object' ) { 1173 } else if ( typeof exports === 'object' ) {
1174   module.exports = defineDocReady( require('eventie') ); 1174   module.exports = defineDocReady( require('eventie') );
1175 } else { 1175 } else {
1176   // browser global 1176   // browser global
1177   window.docReady = defineDocReady( window.eventie ); 1177   window.docReady = defineDocReady( window.eventie );
1178 } 1178 }
1179  1179 
1180 })( window ); 1180 })( window );
1181  1181 
1182 /** 1182 /**
1183  * matchesSelector v1.0.3 1183  * matchesSelector v1.0.3
1184  * matchesSelector( element, '.selector' ) 1184  * matchesSelector( element, '.selector' )
1185  * MIT license 1185  * MIT license
1186  */ 1186  */
1187  1187 
1188 /*jshint browser: true, strict: true, undef: true, unused: true */ 1188 /*jshint browser: true, strict: true, undef: true, unused: true */
1189 /*global define: false, module: false */ 1189 /*global define: false, module: false */
1190  1190 
1191 ( function( ElemProto ) { 1191 ( function( ElemProto ) {
1192  1192 
1193    1193   
1194  1194 
1195   var matchesMethod = ( function() { 1195   var matchesMethod = ( function() {
1196     // check for the standard method name first 1196     // check for the standard method name first
1197     if ( ElemProto.matches ) { 1197     if ( ElemProto.matches ) {
1198       return 'matches'; 1198       return 'matches';
1199     } 1199     }
1200     // check un-prefixed 1200     // check un-prefixed
1201     if ( ElemProto.matchesSelector ) { 1201     if ( ElemProto.matchesSelector ) {
1202       return 'matchesSelector'; 1202       return 'matchesSelector';
1203     } 1203     }
1204     // check vendor prefixes 1204     // check vendor prefixes
1205     var prefixes = [ 'webkit', 'moz', 'ms', 'o' ]; 1205     var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
1206  1206 
1207     for ( var i=0, len = prefixes.length; i < len; i++ ) { 1207     for ( var i=0, len = prefixes.length; i < len; i++ ) {
1208       var prefix = prefixes[i]; 1208       var prefix = prefixes[i];
1209       var method = prefix + 'MatchesSelector'; 1209       var method = prefix + 'MatchesSelector';
1210       if ( ElemProto[ method ] ) { 1210       if ( ElemProto[ method ] ) {
1211         return method; 1211         return method;
1212       } 1212       }
1213     } 1213     }
1214   })(); 1214   })();
1215  1215 
1216   // ----- match ----- // 1216   // ----- match ----- //
1217  1217 
1218   function match( elem, selector ) { 1218   function match( elem, selector ) {
1219     return elem[ matchesMethod ]( selector ); 1219     return elem[ matchesMethod ]( selector );
1220   } 1220   }
1221  1221 
1222   // ----- appendToFragment ----- // 1222   // ----- appendToFragment ----- //
1223  1223 
1224   function checkParent( elem ) { 1224   function checkParent( elem ) {
1225     // not needed if already has parent 1225     // not needed if already has parent
1226     if ( elem.parentNode ) { 1226     if ( elem.parentNode ) {
1227       return; 1227       return;
1228     } 1228     }
1229     var fragment = document.createDocumentFragment(); 1229     var fragment = document.createDocumentFragment();
1230     fragment.appendChild( elem ); 1230     fragment.appendChild( elem );
1231   } 1231   }
1232  1232 
1233   // ----- query ----- // 1233   // ----- query ----- //
1234  1234 
1235   // fall back to using QSA 1235   // fall back to using QSA
1236   // thx @jonathantneal https://gist.github.com/3062955 1236   // thx @jonathantneal https://gist.github.com/3062955
1237   function query( elem, selector ) { 1237   function query( elem, selector ) {
1238     // append to fragment if no parent 1238     // append to fragment if no parent
1239     checkParent( elem ); 1239     checkParent( elem );
1240  1240 
1241     // match elem with all selected elems of parent 1241     // match elem with all selected elems of parent
1242     var elems = elem.parentNode.querySelectorAll( selector ); 1242     var elems = elem.parentNode.querySelectorAll( selector );
1243     for ( var i=0, len = elems.length; i < len; i++ ) { 1243     for ( var i=0, len = elems.length; i < len; i++ ) {
1244       // return true if match 1244       // return true if match
1245       if ( elems[i] === elem ) { 1245       if ( elems[i] === elem ) {
1246         return true; 1246         return true;
1247       } 1247       }
1248     } 1248     }
1249     // otherwise return false 1249     // otherwise return false
1250     return false; 1250     return false;
1251   } 1251   }
1252  1252 
1253   // ----- matchChild ----- // 1253   // ----- matchChild ----- //
1254  1254 
1255   function matchChild( elem, selector ) { 1255   function matchChild( elem, selector ) {
1256     checkParent( elem ); 1256     checkParent( elem );
1257     return match( elem, selector ); 1257     return match( elem, selector );
1258   } 1258   }
1259  1259 
1260   // ----- matchesSelector ----- // 1260   // ----- matchesSelector ----- //
1261  1261 
1262   var matchesSelector; 1262   var matchesSelector;
1263  1263 
1264   if ( matchesMethod ) { 1264   if ( matchesMethod ) {
1265     // IE9 supports matchesSelector, but doesn't work on orphaned elems 1265     // IE9 supports matchesSelector, but doesn't work on orphaned elems
1266     // check for that 1266     // check for that
1267     var div = document.createElement('div'); 1267     var div = document.createElement('div');
1268     var supportsOrphans = match( div, 'div' ); 1268     var supportsOrphans = match( div, 'div' );
1269     matchesSelector = supportsOrphans ? match : matchChild; 1269     matchesSelector = supportsOrphans ? match : matchChild;
1270   } else { 1270   } else {
1271     matchesSelector = query; 1271     matchesSelector = query;
1272   } 1272   }
1273  1273 
1274   // transport 1274   // transport
1275   if ( typeof define === 'function' && define.amd ) { 1275   if ( typeof define === 'function' && define.amd ) {
1276     // AMD 1276     // AMD
1277     define( 'matches-selector/matches-selector',[],function() { 1277     define( 'matches-selector/matches-selector',[],function() {
1278       return matchesSelector; 1278       return matchesSelector;
1279     }); 1279     });
1280   } else if ( typeof exports === 'object' ) { 1280   } else if ( typeof exports === 'object' ) {
1281     module.exports = matchesSelector; 1281     module.exports = matchesSelector;
1282   } 1282   }
1283   else { 1283   else {
1284     // browser global 1284     // browser global
1285     window.matchesSelector = matchesSelector; 1285     window.matchesSelector = matchesSelector;
1286   } 1286   }
1287  1287 
1288 })( Element.prototype ); 1288 })( Element.prototype );
1289  1289 
1290 /** 1290 /**
1291  * Fizzy UI utils v1.0.1 1291  * Fizzy UI utils v1.0.1
1292  * MIT license 1292  * MIT license
1293  */ 1293  */
1294  1294 
1295 /*jshint browser: true, undef: true, unused: true, strict: true */ 1295 /*jshint browser: true, undef: true, unused: true, strict: true */
1296  1296 
1297 ( function( window, factory ) { 1297 ( function( window, factory ) {
1298   /*global define: false, module: false, require: false */ 1298   /*global define: false, module: false, require: false */
1299    1299   
1300   // universal module definition 1300   // universal module definition
1301  1301 
1302   if ( typeof define == 'function' && define.amd ) { 1302   if ( typeof define == 'function' && define.amd ) {
1303     // AMD 1303     // AMD
1304     define( 'fizzy-ui-utils/utils',[ 1304     define( 'fizzy-ui-utils/utils',[
1305       'doc-ready/doc-ready', 1305       'doc-ready/doc-ready',
1306       'matches-selector/matches-selector' 1306       'matches-selector/matches-selector'
1307     ], function( docReady, matchesSelector ) { 1307     ], function( docReady, matchesSelector ) {
1308       return factory( window, docReady, matchesSelector ); 1308       return factory( window, docReady, matchesSelector );
1309     }); 1309     });
1310   } else if ( typeof exports == 'object' ) { 1310   } else if ( typeof exports == 'object' ) {
1311     // CommonJS 1311     // CommonJS
1312     module.exports = factory( 1312     module.exports = factory(
1313       window, 1313       window,
1314       require('doc-ready'), 1314       require('doc-ready'),
1315       require('desandro-matches-selector') 1315       require('desandro-matches-selector')
1316     ); 1316     );
1317   } else { 1317   } else {
1318     // browser global 1318     // browser global
1319     window.fizzyUIUtils = factory( 1319     window.fizzyUIUtils = factory(
1320       window, 1320       window,
1321       window.docReady, 1321       window.docReady,
1322       window.matchesSelector 1322       window.matchesSelector
1323     ); 1323     );
1324   } 1324   }
1325  1325 
1326 }( window, function factory( window, docReady, matchesSelector ) { 1326 }( window, function factory( window, docReady, matchesSelector ) {
1327  1327 
1328  1328 
1329  1329 
1330 var utils = {}; 1330 var utils = {};
1331  1331 
1332 // ----- extend ----- // 1332 // ----- extend ----- //
1333  1333 
1334 // extends objects 1334 // extends objects
1335 utils.extend = function( a, b ) { 1335 utils.extend = function( a, b ) {
1336   for ( var prop in b ) { 1336   for ( var prop in b ) {
1337     a[ prop ] = b[ prop ]; 1337     a[ prop ] = b[ prop ];
1338   } 1338   }
1339   return a; 1339   return a;
1340 }; 1340 };
1341  1341 
1342 // ----- modulo ----- // 1342 // ----- modulo ----- //
1343  1343 
1344 utils.modulo = function( num, div ) { 1344 utils.modulo = function( num, div ) {
1345   return ( ( num % div ) + div ) % div; 1345   return ( ( num % div ) + div ) % div;
1346 }; 1346 };
1347  1347 
1348 // ----- isArray ----- // 1348 // ----- isArray ----- //
1349    1349   
1350 var objToString = Object.prototype.toString; 1350 var objToString = Object.prototype.toString;
1351 utils.isArray = function( obj ) { 1351 utils.isArray = function( obj ) {
1352   return objToString.call( obj ) == '[object Array]'; 1352   return objToString.call( obj ) == '[object Array]';
1353 }; 1353 };
1354  1354 
1355 // ----- makeArray ----- // 1355 // ----- makeArray ----- //
1356  1356 
1357 // turn element or nodeList into an array 1357 // turn element or nodeList into an array
1358 utils.makeArray = function( obj ) { 1358 utils.makeArray = function( obj ) {
1359   var ary = []; 1359   var ary = [];
1360   if ( utils.isArray( obj ) ) { 1360   if ( utils.isArray( obj ) ) {
1361     // use object if already an array 1361     // use object if already an array
1362     ary = obj; 1362     ary = obj;
1363   } else if ( obj && typeof obj.length == 'number' ) { 1363   } else if ( obj && typeof obj.length == 'number' ) {
1364     // convert nodeList to array 1364     // convert nodeList to array
1365     for ( var i=0, len = obj.length; i < len; i++ ) { 1365     for ( var i=0, len = obj.length; i < len; i++ ) {
1366       ary.push( obj[i] ); 1366       ary.push( obj[i] );
1367     } 1367     }
1368   } else { 1368   } else {
1369     // array of single index 1369     // array of single index
1370     ary.push( obj ); 1370     ary.push( obj );
1371   } 1371   }
1372   return ary; 1372   return ary;
1373 }; 1373 };
1374  1374 
1375 // ----- indexOf ----- // 1375 // ----- indexOf ----- //
1376  1376 
1377 // index of helper cause IE8 1377 // index of helper cause IE8
1378 utils.indexOf = Array.prototype.indexOf ? function( ary, obj ) { 1378 utils.indexOf = Array.prototype.indexOf ? function( ary, obj ) {
1379     return ary.indexOf( obj ); 1379     return ary.indexOf( obj );
1380   } : function( ary, obj ) { 1380   } : function( ary, obj ) {
1381     for ( var i=0, len = ary.length; i < len; i++ ) { 1381     for ( var i=0, len = ary.length; i < len; i++ ) {
1382       if ( ary[i] === obj ) { 1382       if ( ary[i] === obj ) {
1383         return i; 1383         return i;
1384       } 1384       }
1385     } 1385     }
1386     return -1; 1386     return -1;
1387   }; 1387   };
1388  1388 
1389 // ----- removeFrom ----- // 1389 // ----- removeFrom ----- //
1390  1390 
1391 utils.removeFrom = function( ary, obj ) { 1391 utils.removeFrom = function( ary, obj ) {
1392   var index = utils.indexOf( ary, obj ); 1392   var index = utils.indexOf( ary, obj );
1393   if ( index != -1 ) { 1393   if ( index != -1 ) {
1394     ary.splice( index, 1 ); 1394     ary.splice( index, 1 );
1395   } 1395   }
1396 }; 1396 };
1397  1397 
1398 // ----- isElement ----- // 1398 // ----- isElement ----- //
1399  1399 
1400 // http://stackoverflow.com/a/384380/182183 1400 // http://stackoverflow.com/a/384380/182183
1401 utils.isElement = ( typeof HTMLElement == 'function' || typeof HTMLElement == 'object' ) ? 1401 utils.isElement = ( typeof HTMLElement == 'function' || typeof HTMLElement == 'object' ) ?
1402   function isElementDOM2( obj ) { 1402   function isElementDOM2( obj ) {
1403     return obj instanceof HTMLElement; 1403     return obj instanceof HTMLElement;
1404   } : 1404   } :
1405   function isElementQuirky( obj ) { 1405   function isElementQuirky( obj ) {
1406     return obj && typeof obj == 'object' && 1406     return obj && typeof obj == 'object' &&
1407       obj.nodeType == 1 && typeof obj.nodeName == 'string'; 1407       obj.nodeType == 1 && typeof obj.nodeName == 'string';
1408   }; 1408   };
1409  1409 
1410 // ----- setText ----- // 1410 // ----- setText ----- //
1411  1411 
1412 utils.setText = ( function() { 1412 utils.setText = ( function() {
1413   var setTextProperty; 1413   var setTextProperty;
1414   function setText( elem, text ) { 1414   function setText( elem, text ) {
1415     // only check setTextProperty once 1415     // only check setTextProperty once
1416     setTextProperty = setTextProperty || ( document.documentElement.textContent !== undefined ? 'textContent' : 'innerText' ); 1416     setTextProperty = setTextProperty || ( document.documentElement.textContent !== undefined ? 'textContent' : 'innerText' );
1417     elem[ setTextProperty ] = text; 1417     elem[ setTextProperty ] = text;
1418   } 1418   }
1419   return setText; 1419   return setText;
1420 })(); 1420 })();
1421  1421 
1422 // ----- getParent ----- // 1422 // ----- getParent ----- //
1423  1423 
1424 utils.getParent = function( elem, selector ) { 1424 utils.getParent = function( elem, selector ) {
1425   while ( elem != document.body ) { 1425   while ( elem != document.body ) {
1426     elem = elem.parentNode; 1426     elem = elem.parentNode;
1427     if ( matchesSelector( elem, selector ) ) { 1427     if ( matchesSelector( elem, selector ) ) {
1428       return elem; 1428       return elem;
1429     } 1429     }
1430   } 1430   }
1431 }; 1431 };
1432  1432 
1433 // ----- getQueryElement ----- // 1433 // ----- getQueryElement ----- //
1434  1434 
1435 // use element as selector string 1435 // use element as selector string
1436 utils.getQueryElement = function( elem ) { 1436 utils.getQueryElement = function( elem ) {
1437   if ( typeof elem == 'string' ) { 1437   if ( typeof elem == 'string' ) {
1438     return document.querySelector( elem ); 1438     return document.querySelector( elem );
1439   } 1439   }
1440   return elem; 1440   return elem;
1441 }; 1441 };
1442  1442 
1443 // ----- handleEvent ----- // 1443 // ----- handleEvent ----- //
1444  1444 
1445 // enable .ontype to trigger from .addEventListener( elem, 'type' ) 1445 // enable .ontype to trigger from .addEventListener( elem, 'type' )
1446 utils.handleEvent = function( event ) { 1446 utils.handleEvent = function( event ) {
1447   var method = 'on' + event.type; 1447   var method = 'on' + event.type;
1448   if ( this[ method ] ) { 1448   if ( this[ method ] ) {
1449     this[ method ]( event ); 1449     this[ method ]( event );
1450   } 1450   }
1451 }; 1451 };
1452  1452 
1453 // ----- filterFindElements ----- // 1453 // ----- filterFindElements ----- //
1454  1454 
1455 utils.filterFindElements = function( elems, selector ) { 1455 utils.filterFindElements = function( elems, selector ) {
1456   // make array of elems 1456   // make array of elems
1457   elems = utils.makeArray( elems ); 1457   elems = utils.makeArray( elems );
1458   var ffElems = []; 1458   var ffElems = [];
1459  1459 
1460   for ( var i=0, len = elems.length; i < len; i++ ) { 1460   for ( var i=0, len = elems.length; i < len; i++ ) {
1461     var elem = elems[i]; 1461     var elem = elems[i];
1462     // check that elem is an actual element 1462     // check that elem is an actual element
1463     if ( !utils.isElement( elem ) ) { 1463     if ( !utils.isElement( elem ) ) {
1464       continue; 1464       continue;
1465     } 1465     }
1466     // filter & find items if we have a selector 1466     // filter & find items if we have a selector
1467     if ( selector ) { 1467     if ( selector ) {
1468       // filter siblings 1468       // filter siblings
1469       if ( matchesSelector( elem, selector ) ) { 1469       if ( matchesSelector( elem, selector ) ) {
1470         ffElems.push( elem ); 1470         ffElems.push( elem );
1471       } 1471       }
1472       // find children 1472       // find children
1473       var childElems = elem.querySelectorAll( selector ); 1473       var childElems = elem.querySelectorAll( selector );
1474       // concat childElems to filterFound array 1474       // concat childElems to filterFound array
1475       for ( var j=0, jLen = childElems.length; j < jLen; j++ ) { 1475       for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
1476         ffElems.push( childElems[j] ); 1476         ffElems.push( childElems[j] );
1477       } 1477       }
1478     } else { 1478     } else {
1479       ffElems.push( elem ); 1479       ffElems.push( elem );
1480     } 1480     }
1481   } 1481   }
1482  1482 
1483   return ffElems; 1483   return ffElems;
1484 }; 1484 };
1485  1485 
1486 // ----- debounceMethod ----- // 1486 // ----- debounceMethod ----- //
1487  1487 
1488 utils.debounceMethod = function( _class, methodName, threshold ) { 1488 utils.debounceMethod = function( _class, methodName, threshold ) {
1489   // original method 1489   // original method
1490   var method = _class.prototype[ methodName ]; 1490   var method = _class.prototype[ methodName ];
1491   var timeoutName = methodName + 'Timeout'; 1491   var timeoutName = methodName + 'Timeout';
1492  1492 
1493   _class.prototype[ methodName ] = function() { 1493   _class.prototype[ methodName ] = function() {
1494     var timeout = this[ timeoutName ]; 1494     var timeout = this[ timeoutName ];
1495     if ( timeout ) { 1495     if ( timeout ) {
1496       clearTimeout( timeout ); 1496       clearTimeout( timeout );
1497     } 1497     }
1498     var args = arguments; 1498     var args = arguments;
1499  1499 
1500     var _this = this; 1500     var _this = this;
1501     this[ timeoutName ] = setTimeout( function() { 1501     this[ timeoutName ] = setTimeout( function() {
1502       method.apply( _this, args ); 1502       method.apply( _this, args );
1503       delete _this[ timeoutName ]; 1503       delete _this[ timeoutName ];
1504     }, threshold || 100 ); 1504     }, threshold || 100 );
1505   }; 1505   };
1506 }; 1506 };
1507  1507 
1508 // ----- htmlInit ----- // 1508 // ----- htmlInit ----- //
1509  1509 
1510 // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ 1510 // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1511 utils.toDashed = function( str ) { 1511 utils.toDashed = function( str ) {
1512   return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { 1512   return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
1513     return $1 + '-' + $2; 1513     return $1 + '-' + $2;
1514   }).toLowerCase(); 1514   }).toLowerCase();
1515 }; 1515 };
1516  1516 
1517 var console = window.console; 1517 var console = window.console;
1518 /** 1518 /**
1519  * allow user to initialize classes via .js-namespace class 1519  * allow user to initialize classes via .js-namespace class
1520  * htmlInit( Widget, 'widgetName' ) 1520  * htmlInit( Widget, 'widgetName' )
1521  * options are parsed from data-namespace-option attribute 1521  * options are parsed from data-namespace-option attribute
1522  */ 1522  */
1523 utils.htmlInit = function( WidgetClass, namespace ) { 1523 utils.htmlInit = function( WidgetClass, namespace ) {
1524   docReady( function() { 1524   docReady( function() {
1525     var dashedNamespace = utils.toDashed( namespace ); 1525     var dashedNamespace = utils.toDashed( namespace );
1526     var elems = document.querySelectorAll( '.js-' + dashedNamespace ); 1526     var elems = document.querySelectorAll( '.js-' + dashedNamespace );
1527     var dataAttr = 'data-' + dashedNamespace + '-options'; 1527     var dataAttr = 'data-' + dashedNamespace + '-options';
1528  1528 
1529     for ( var i=0, len = elems.length; i < len; i++ ) { 1529     for ( var i=0, len = elems.length; i < len; i++ ) {
1530       var elem = elems[i]; 1530       var elem = elems[i];
1531       var attr = elem.getAttribute( dataAttr ); 1531       var attr = elem.getAttribute( dataAttr );
1532       var options; 1532       var options;
1533       try { 1533       try {
1534         options = attr && JSON.parse( attr ); 1534         options = attr && JSON.parse( attr );
1535       } catch ( error ) { 1535       } catch ( error ) {
1536         // log error, do not initialize 1536         // log error, do not initialize
1537         if ( console ) { 1537         if ( console ) {
1538           console.error( 'Error parsing ' + dataAttr + ' on ' + 1538           console.error( 'Error parsing ' + dataAttr + ' on ' +
1539             elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' + 1539             elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
1540             error ); 1540             error );
1541         } 1541         }
1542         continue; 1542         continue;
1543       } 1543       }
1544       // initialize 1544       // initialize
1545       var instance = new WidgetClass( elem, options ); 1545       var instance = new WidgetClass( elem, options );
1546       // make available via $().data('layoutname') 1546       // make available via $().data('layoutname')
1547       var jQuery = window.jQuery; 1547       var jQuery = window.jQuery;
1548       if ( jQuery ) { 1548       if ( jQuery ) {
1549         jQuery.data( elem, namespace, instance ); 1549         jQuery.data( elem, namespace, instance );
1550       } 1550       }
1551     } 1551     }
1552   }); 1552   });
1553 }; 1553 };
1554  1554 
1555 // -----  ----- // 1555 // -----  ----- //
1556  1556 
1557 return utils; 1557 return utils;
1558  1558 
1559 })); 1559 }));
1560  1560 
1561 /** 1561 /**
1562  * Outlayer Item 1562  * Outlayer Item
1563  */ 1563  */
1564  1564 
1565 ( function( window, factory ) { 1565 ( function( window, factory ) {
1566    1566   
1567   // universal module definition 1567   // universal module definition
1568   if ( typeof define === 'function' && define.amd ) { 1568   if ( typeof define === 'function' && define.amd ) {
1569     // AMD 1569     // AMD
1570     define( 'outlayer/item',[ 1570     define( 'outlayer/item',[
1571         'eventEmitter/EventEmitter', 1571         'eventEmitter/EventEmitter',
1572         'get-size/get-size', 1572         'get-size/get-size',
1573         'get-style-property/get-style-property', 1573         'get-style-property/get-style-property',
1574         'fizzy-ui-utils/utils' 1574         'fizzy-ui-utils/utils'
1575       ], 1575       ],
1576       function( EventEmitter, getSize, getStyleProperty, utils ) { 1576       function( EventEmitter, getSize, getStyleProperty, utils ) {
1577         return factory( window, EventEmitter, getSize, getStyleProperty, utils ); 1577         return factory( window, EventEmitter, getSize, getStyleProperty, utils );
1578       } 1578       }
1579     ); 1579     );
1580   } else if (typeof exports === 'object') { 1580   } else if (typeof exports === 'object') {
1581     // CommonJS 1581     // CommonJS
1582     module.exports = factory( 1582     module.exports = factory(
1583       window, 1583       window,
1584       require('wolfy87-eventemitter'), 1584       require('wolfy87-eventemitter'),
1585       require('get-size'), 1585       require('get-size'),
1586       require('desandro-get-style-property'), 1586       require('desandro-get-style-property'),
1587       require('fizzy-ui-utils') 1587       require('fizzy-ui-utils')
1588     ); 1588     );
1589   } else { 1589   } else {
1590     // browser global 1590     // browser global
1591     window.Outlayer = {}; 1591     window.Outlayer = {};
1592     window.Outlayer.Item = factory( 1592     window.Outlayer.Item = factory(
1593       window, 1593       window,
1594       window.EventEmitter, 1594       window.EventEmitter,
1595       window.getSize, 1595       window.getSize,
1596       window.getStyleProperty, 1596       window.getStyleProperty,
1597       window.fizzyUIUtils 1597       window.fizzyUIUtils
1598     ); 1598     );
1599   } 1599   }
1600  1600 
1601 }( window, function factory( window, EventEmitter, getSize, getStyleProperty, utils ) { 1601 }( window, function factory( window, EventEmitter, getSize, getStyleProperty, utils ) {
1602  1602 
1603  1603 
1604 // ----- helpers ----- // 1604 // ----- helpers ----- //
1605  1605 
1606 var getComputedStyle = window.getComputedStyle; 1606 var getComputedStyle = window.getComputedStyle;
1607 var getStyle = getComputedStyle ? 1607 var getStyle = getComputedStyle ?
1608   function( elem ) { 1608   function( elem ) {
1609     return getComputedStyle( elem, null ); 1609     return getComputedStyle( elem, null );
1610   } : 1610   } :
1611   function( elem ) { 1611   function( elem ) {
1612     return elem.currentStyle; 1612     return elem.currentStyle;
1613   }; 1613   };
1614  1614 
1615  1615 
1616 function isEmptyObj( obj ) { 1616 function isEmptyObj( obj ) {
1617   for ( var prop in obj ) { 1617   for ( var prop in obj ) {
1618     return false; 1618     return false;
1619   } 1619   }
1620   prop = null; 1620   prop = null;
1621   return true; 1621   return true;
1622 } 1622 }
1623  1623 
1624 // -------------------------- CSS3 support -------------------------- // 1624 // -------------------------- CSS3 support -------------------------- //
1625  1625 
1626 var transitionProperty = getStyleProperty('transition'); 1626 var transitionProperty = getStyleProperty('transition');
1627 var transformProperty = getStyleProperty('transform'); 1627 var transformProperty = getStyleProperty('transform');
1628 var supportsCSS3 = transitionProperty && transformProperty; 1628 var supportsCSS3 = transitionProperty && transformProperty;
1629 var is3d = !!getStyleProperty('perspective'); 1629 var is3d = !!getStyleProperty('perspective');
1630  1630 
1631 var transitionEndEvent = { 1631 var transitionEndEvent = {
1632   WebkitTransition: 'webkitTransitionEnd', 1632   WebkitTransition: 'webkitTransitionEnd',
1633   MozTransition: 'transitionend', 1633   MozTransition: 'transitionend',
1634   OTransition: 'otransitionend', 1634   OTransition: 'otransitionend',
1635   transition: 'transitionend' 1635   transition: 'transitionend'
1636 }[ transitionProperty ]; 1636 }[ transitionProperty ];
1637  1637 
1638 // properties that could have vendor prefix 1638 // properties that could have vendor prefix
1639 var prefixableProperties = [ 1639 var prefixableProperties = [
1640   'transform', 1640   'transform',
1641   'transition', 1641   'transition',
1642   'transitionDuration', 1642   'transitionDuration',
1643   'transitionProperty' 1643   'transitionProperty'
1644 ]; 1644 ];
1645  1645 
1646 // cache all vendor properties 1646 // cache all vendor properties
1647 var vendorProperties = ( function() { 1647 var vendorProperties = ( function() {
1648   var cache = {}; 1648   var cache = {};
1649   for ( var i=0, len = prefixableProperties.length; i < len; i++ ) { 1649   for ( var i=0, len = prefixableProperties.length; i < len; i++ ) {
1650     var prop = prefixableProperties[i]; 1650     var prop = prefixableProperties[i];
1651     var supportedProp = getStyleProperty( prop ); 1651     var supportedProp = getStyleProperty( prop );
1652     if ( supportedProp && supportedProp !== prop ) { 1652     if ( supportedProp && supportedProp !== prop ) {
1653       cache[ prop ] = supportedProp; 1653       cache[ prop ] = supportedProp;
1654     } 1654     }
1655   } 1655   }
1656   return cache; 1656   return cache;
1657 })(); 1657 })();
1658  1658 
1659 // -------------------------- Item -------------------------- // 1659 // -------------------------- Item -------------------------- //
1660  1660 
1661 function Item( element, layout ) { 1661 function Item( element, layout ) {
1662   if ( !element ) { 1662   if ( !element ) {
1663     return; 1663     return;
1664   } 1664   }
1665  1665 
1666   this.element = element; 1666   this.element = element;
1667   // parent layout class, i.e. Masonry, Isotope, or Packery 1667   // parent layout class, i.e. Masonry, Isotope, or Packery
1668   this.layout = layout; 1668   this.layout = layout;
1669   this.position = { 1669   this.position = {
1670     x: 0, 1670     x: 0,
1671     y: 0 1671     y: 0
1672   }; 1672   };
1673  1673 
1674   this._create(); 1674   this._create();
1675 } 1675 }
1676  1676 
1677 // inherit EventEmitter 1677 // inherit EventEmitter
1678 utils.extend( Item.prototype, EventEmitter.prototype ); 1678 utils.extend( Item.prototype, EventEmitter.prototype );
1679  1679 
1680 Item.prototype._create = function() { 1680 Item.prototype._create = function() {
1681   // transition objects 1681   // transition objects
1682   this._transn = { 1682   this._transn = {
1683     ingProperties: {}, 1683     ingProperties: {},
1684     clean: {}, 1684     clean: {},
1685     onEnd: {} 1685     onEnd: {}
1686   }; 1686   };
1687  1687 
1688   this.css({ 1688   this.css({
1689     position: 'absolute' 1689     position: 'absolute'
1690   }); 1690   });
1691 }; 1691 };
1692  1692 
1693 // trigger specified handler for event type 1693 // trigger specified handler for event type
1694 Item.prototype.handleEvent = function( event ) { 1694 Item.prototype.handleEvent = function( event ) {
1695   var method = 'on' + event.type; 1695   var method = 'on' + event.type;
1696   if ( this[ method ] ) { 1696   if ( this[ method ] ) {
1697     this[ method ]( event ); 1697     this[ method ]( event );
1698   } 1698   }
1699 }; 1699 };
1700  1700 
1701 Item.prototype.getSize = function() { 1701 Item.prototype.getSize = function() {
1702   this.size = getSize( this.element ); 1702   this.size = getSize( this.element );
1703 }; 1703 };
1704  1704 
1705 /** 1705 /**
1706  * apply CSS styles to element 1706  * apply CSS styles to element
1707  * @param {Object} style 1707  * @param {Object} style
1708  */ 1708  */
1709 Item.prototype.css = function( style ) { 1709 Item.prototype.css = function( style ) {
1710   var elemStyle = this.element.style; 1710   var elemStyle = this.element.style;
1711  1711 
1712   for ( var prop in style ) { 1712   for ( var prop in style ) {
1713     // use vendor property if available 1713     // use vendor property if available
1714     var supportedProp = vendorProperties[ prop ] || prop; 1714     var supportedProp = vendorProperties[ prop ] || prop;
1715     elemStyle[ supportedProp ] = style[ prop ]; 1715     elemStyle[ supportedProp ] = style[ prop ];
1716   } 1716   }
1717 }; 1717 };
1718  1718 
1719  // measure position, and sets it 1719  // measure position, and sets it
1720 Item.prototype.getPosition = function() { 1720 Item.prototype.getPosition = function() {
1721   var style = getStyle( this.element ); 1721   var style = getStyle( this.element );
1722   var layoutOptions = this.layout.options; 1722   var layoutOptions = this.layout.options;
1723   var isOriginLeft = layoutOptions.isOriginLeft; 1723   var isOriginLeft = layoutOptions.isOriginLeft;
1724   var isOriginTop = layoutOptions.isOriginTop; 1724   var isOriginTop = layoutOptions.isOriginTop;
1725   var xValue = style[ isOriginLeft ? 'left' : 'right' ]; 1725   var xValue = style[ isOriginLeft ? 'left' : 'right' ];
1726   var yValue = style[ isOriginTop ? 'top' : 'bottom' ]; 1726   var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
1727   // convert percent to pixels 1727   // convert percent to pixels
1728   var layoutSize = this.layout.size; 1728   var layoutSize = this.layout.size;
1729   var x = xValue.indexOf('%') != -1 ? 1729   var x = xValue.indexOf('%') != -1 ?
1730     ( parseFloat( xValue ) / 100 ) * layoutSize.width : parseInt( xValue, 10 ); 1730     ( parseFloat( xValue ) / 100 ) * layoutSize.width : parseInt( xValue, 10 );
1731   var y = yValue.indexOf('%') != -1 ? 1731   var y = yValue.indexOf('%') != -1 ?
1732     ( parseFloat( yValue ) / 100 ) * layoutSize.height : parseInt( yValue, 10 ); 1732     ( parseFloat( yValue ) / 100 ) * layoutSize.height : parseInt( yValue, 10 );
1733  1733 
1734   // clean up 'auto' or other non-integer values 1734   // clean up 'auto' or other non-integer values
1735   x = isNaN( x ) ? 0 : x; 1735   x = isNaN( x ) ? 0 : x;
1736   y = isNaN( y ) ? 0 : y; 1736   y = isNaN( y ) ? 0 : y;
1737   // remove padding from measurement 1737   // remove padding from measurement
1738   x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; 1738   x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
1739   y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; 1739   y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
1740  1740 
1741   this.position.x = x; 1741   this.position.x = x;
1742   this.position.y = y; 1742   this.position.y = y;
1743 }; 1743 };
1744  1744 
1745 // set settled position, apply padding 1745 // set settled position, apply padding
1746 Item.prototype.layoutPosition = function() { 1746 Item.prototype.layoutPosition = function() {
1747   var layoutSize = this.layout.size; 1747   var layoutSize = this.layout.size;
1748   var layoutOptions = this.layout.options; 1748   var layoutOptions = this.layout.options;
1749   var style = {}; 1749   var style = {};
1750  1750 
1751   // x 1751   // x
1752   var xPadding = layoutOptions.isOriginLeft ? 'paddingLeft' : 'paddingRight'; 1752   var xPadding = layoutOptions.isOriginLeft ? 'paddingLeft' : 'paddingRight';
1753   var xProperty = layoutOptions.isOriginLeft ? 'left' : 'right'; 1753   var xProperty = layoutOptions.isOriginLeft ? 'left' : 'right';
1754   var xResetProperty = layoutOptions.isOriginLeft ? 'right' : 'left'; 1754   var xResetProperty = layoutOptions.isOriginLeft ? 'right' : 'left';
1755  1755 
1756   var x = this.position.x + layoutSize[ xPadding ]; 1756   var x = this.position.x + layoutSize[ xPadding ];
1757   // set in percentage or pixels 1757   // set in percentage or pixels
1758   style[ xProperty ] = this.getXValue( x ); 1758   style[ xProperty ] = this.getXValue( x );
1759   // reset other property 1759   // reset other property
1760   style[ xResetProperty ] = ''; 1760   style[ xResetProperty ] = '';
1761  1761 
1762   // y 1762   // y
1763   var yPadding = layoutOptions.isOriginTop ? 'paddingTop' : 'paddingBottom'; 1763   var yPadding = layoutOptions.isOriginTop ? 'paddingTop' : 'paddingBottom';
1764   var yProperty = layoutOptions.isOriginTop ? 'top' : 'bottom'; 1764   var yProperty = layoutOptions.isOriginTop ? 'top' : 'bottom';
1765   var yResetProperty = layoutOptions.isOriginTop ? 'bottom' : 'top'; 1765   var yResetProperty = layoutOptions.isOriginTop ? 'bottom' : 'top';
1766  1766 
1767   var y = this.position.y + layoutSize[ yPadding ]; 1767   var y = this.position.y + layoutSize[ yPadding ];
1768   // set in percentage or pixels 1768   // set in percentage or pixels
1769   style[ yProperty ] = this.getYValue( y ); 1769   style[ yProperty ] = this.getYValue( y );
1770   // reset other property 1770   // reset other property
1771   style[ yResetProperty ] = ''; 1771   style[ yResetProperty ] = '';
1772  1772 
1773   this.css( style ); 1773   this.css( style );
1774   this.emitEvent( 'layout', [ this ] ); 1774   this.emitEvent( 'layout', [ this ] );
1775 }; 1775 };
1776  1776 
1777 Item.prototype.getXValue = function( x ) { 1777 Item.prototype.getXValue = function( x ) {
1778   var layoutOptions = this.layout.options; 1778   var layoutOptions = this.layout.options;
1779   return layoutOptions.percentPosition && !layoutOptions.isHorizontal ? 1779   return layoutOptions.percentPosition && !layoutOptions.isHorizontal ?
1780     ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px'; 1780     ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
1781 }; 1781 };
1782  1782 
1783 Item.prototype.getYValue = function( y ) { 1783 Item.prototype.getYValue = function( y ) {
1784   var layoutOptions = this.layout.options; 1784   var layoutOptions = this.layout.options;
1785   return layoutOptions.percentPosition && layoutOptions.isHorizontal ? 1785   return layoutOptions.percentPosition && layoutOptions.isHorizontal ?
1786     ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px'; 1786     ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
1787 }; 1787 };
1788  1788 
1789  1789 
1790 Item.prototype._transitionTo = function( x, y ) { 1790 Item.prototype._transitionTo = function( x, y ) {
1791   this.getPosition(); 1791   this.getPosition();
1792   // get current x & y from top/left 1792   // get current x & y from top/left
1793   var curX = this.position.x; 1793   var curX = this.position.x;
1794   var curY = this.position.y; 1794   var curY = this.position.y;
1795  1795 
1796   var compareX = parseInt( x, 10 ); 1796   var compareX = parseInt( x, 10 );
1797   var compareY = parseInt( y, 10 ); 1797   var compareY = parseInt( y, 10 );
1798   var didNotMove = compareX === this.position.x && compareY === this.position.y; 1798   var didNotMove = compareX === this.position.x && compareY === this.position.y;
1799  1799 
1800   // save end position 1800   // save end position
1801   this.setPosition( x, y ); 1801   this.setPosition( x, y );
1802  1802 
1803   // if did not move and not transitioning, just go to layout 1803   // if did not move and not transitioning, just go to layout
1804   if ( didNotMove && !this.isTransitioning ) { 1804   if ( didNotMove && !this.isTransitioning ) {
1805     this.layoutPosition(); 1805     this.layoutPosition();
1806     return; 1806     return;
1807   } 1807   }
1808  1808 
1809   var transX = x - curX; 1809   var transX = x - curX;
1810   var transY = y - curY; 1810   var transY = y - curY;
1811   var transitionStyle = {}; 1811   var transitionStyle = {};
1812   transitionStyle.transform = this.getTranslate( transX, transY ); 1812   transitionStyle.transform = this.getTranslate( transX, transY );
1813  1813 
1814   this.transition({ 1814   this.transition({
1815     to: transitionStyle, 1815     to: transitionStyle,
1816     onTransitionEnd: { 1816     onTransitionEnd: {
1817       transform: this.layoutPosition 1817       transform: this.layoutPosition
1818     }, 1818     },
1819     isCleaning: true 1819     isCleaning: true
1820   }); 1820   });
1821 }; 1821 };
1822  1822 
1823 Item.prototype.getTranslate = function( x, y ) { 1823 Item.prototype.getTranslate = function( x, y ) {
1824   // flip cooridinates if origin on right or bottom 1824   // flip cooridinates if origin on right or bottom
1825   var layoutOptions = this.layout.options; 1825   var layoutOptions = this.layout.options;
1826   x = layoutOptions.isOriginLeft ? x : -x; 1826   x = layoutOptions.isOriginLeft ? x : -x;
1827   y = layoutOptions.isOriginTop ? y : -y; 1827   y = layoutOptions.isOriginTop ? y : -y;
1828  1828 
1829   if ( is3d ) { 1829   if ( is3d ) {
1830     return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; 1830     return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
1831   } 1831   }
1832  1832 
1833   return 'translate(' + x + 'px, ' + y + 'px)'; 1833   return 'translate(' + x + 'px, ' + y + 'px)';
1834 }; 1834 };
1835  1835 
1836 // non transition + transform support 1836 // non transition + transform support
1837 Item.prototype.goTo = function( x, y ) { 1837 Item.prototype.goTo = function( x, y ) {
1838   this.setPosition( x, y ); 1838   this.setPosition( x, y );
1839   this.layoutPosition(); 1839   this.layoutPosition();
1840 }; 1840 };
1841  1841 
1842 // use transition and transforms if supported 1842 // use transition and transforms if supported
1843 Item.prototype.moveTo = supportsCSS3 ? 1843 Item.prototype.moveTo = supportsCSS3 ?
1844   Item.prototype._transitionTo : Item.prototype.goTo; 1844   Item.prototype._transitionTo : Item.prototype.goTo;
1845  1845 
1846 Item.prototype.setPosition = function( x, y ) { 1846 Item.prototype.setPosition = function( x, y ) {
1847   this.position.x = parseInt( x, 10 ); 1847   this.position.x = parseInt( x, 10 );
1848   this.position.y = parseInt( y, 10 ); 1848   this.position.y = parseInt( y, 10 );
1849 }; 1849 };
1850  1850 
1851 // ----- transition ----- // 1851 // ----- transition ----- //
1852  1852 
1853 /** 1853 /**
1854  * @param {Object} style - CSS 1854  * @param {Object} style - CSS
1855  * @param {Function} onTransitionEnd 1855  * @param {Function} onTransitionEnd
1856  */ 1856  */
1857  1857 
1858 // non transition, just trigger callback 1858 // non transition, just trigger callback
1859 Item.prototype._nonTransition = function( args ) { 1859 Item.prototype._nonTransition = function( args ) {
1860   this.css( args.to ); 1860   this.css( args.to );
1861   if ( args.isCleaning ) { 1861   if ( args.isCleaning ) {
1862     this._removeStyles( args.to ); 1862     this._removeStyles( args.to );
1863   } 1863   }
1864   for ( var prop in args.onTransitionEnd ) { 1864   for ( var prop in args.onTransitionEnd ) {
1865     args.onTransitionEnd[ prop ].call( this ); 1865     args.onTransitionEnd[ prop ].call( this );
1866   } 1866   }
1867 }; 1867 };
1868  1868 
1869 /** 1869 /**
1870  * proper transition 1870  * proper transition
1871  * @param {Object} args - arguments 1871  * @param {Object} args - arguments
1872  *   @param {Object} to - style to transition to 1872  *   @param {Object} to - style to transition to
1873  *   @param {Object} from - style to start transition from 1873  *   @param {Object} from - style to start transition from
1874  *   @param {Boolean} isCleaning - removes transition styles after transition 1874  *   @param {Boolean} isCleaning - removes transition styles after transition
1875  *   @param {Function} onTransitionEnd - callback 1875  *   @param {Function} onTransitionEnd - callback
1876  */ 1876  */
1877 Item.prototype._transition = function( args ) { 1877 Item.prototype._transition = function( args ) {
1878   // redirect to nonTransition if no transition duration 1878   // redirect to nonTransition if no transition duration
1879   if ( !parseFloat( this.layout.options.transitionDuration ) ) { 1879   if ( !parseFloat( this.layout.options.transitionDuration ) ) {
1880     this._nonTransition( args ); 1880     this._nonTransition( args );
1881     return; 1881     return;
1882   } 1882   }
1883  1883 
1884   var _transition = this._transn; 1884   var _transition = this._transn;
1885   // keep track of onTransitionEnd callback by css property 1885   // keep track of onTransitionEnd callback by css property
1886   for ( var prop in args.onTransitionEnd ) { 1886   for ( var prop in args.onTransitionEnd ) {
1887     _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; 1887     _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
1888   } 1888   }
1889   // keep track of properties that are transitioning 1889   // keep track of properties that are transitioning
1890   for ( prop in args.to ) { 1890   for ( prop in args.to ) {
1891     _transition.ingProperties[ prop ] = true; 1891     _transition.ingProperties[ prop ] = true;
1892     // keep track of properties to clean up when transition is done 1892     // keep track of properties to clean up when transition is done
1893     if ( args.isCleaning ) { 1893     if ( args.isCleaning ) {
1894       _transition.clean[ prop ] = true; 1894       _transition.clean[ prop ] = true;
1895     } 1895     }
1896   } 1896   }
1897  1897 
1898   // set from styles 1898   // set from styles
1899   if ( args.from ) { 1899   if ( args.from ) {
1900     this.css( args.from ); 1900     this.css( args.from );
1901     // force redraw. http://blog.alexmaccaw.com/css-transitions 1901     // force redraw. http://blog.alexmaccaw.com/css-transitions
1902     var h = this.element.offsetHeight; 1902     var h = this.element.offsetHeight;
1903     // hack for JSHint to hush about unused var 1903     // hack for JSHint to hush about unused var
1904     h = null; 1904     h = null;
1905   } 1905   }
1906   // enable transition 1906   // enable transition
1907   this.enableTransition( args.to ); 1907   this.enableTransition( args.to );
1908   // set styles that are transitioning 1908   // set styles that are transitioning
1909   this.css( args.to ); 1909   this.css( args.to );
1910  1910 
1911   this.isTransitioning = true; 1911   this.isTransitioning = true;
1912  1912 
1913 }; 1913 };
1914  1914 
1915 // dash before all cap letters, including first for 1915 // dash before all cap letters, including first for
1916 // WebkitTransform => -webkit-transform 1916 // WebkitTransform => -webkit-transform
1917 function toDashedAll( str ) { 1917 function toDashedAll( str ) {
1918   return str.replace( /([A-Z])/g, function( $1 ) { 1918   return str.replace( /([A-Z])/g, function( $1 ) {
1919     return '-' + $1.toLowerCase(); 1919     return '-' + $1.toLowerCase();
1920   }); 1920   });
1921 } 1921 }
1922  1922 
1923 var transitionProps = 'opacity,' + 1923 var transitionProps = 'opacity,' +
1924   toDashedAll( vendorProperties.transform || 'transform' ); 1924   toDashedAll( vendorProperties.transform || 'transform' );
1925  1925 
1926 Item.prototype.enableTransition = function(/* style */) { 1926 Item.prototype.enableTransition = function(/* style */) {
1927   // HACK changing transitionProperty during a transition 1927   // HACK changing transitionProperty during a transition
1928   // will cause transition to jump 1928   // will cause transition to jump
1929   if ( this.isTransitioning ) { 1929   if ( this.isTransitioning ) {
1930     return; 1930     return;
1931   } 1931   }
1932  1932 
1933   // make `transition: foo, bar, baz` from style object 1933   // make `transition: foo, bar, baz` from style object
1934   // HACK un-comment this when enableTransition can work 1934   // HACK un-comment this when enableTransition can work
1935   // while a transition is happening 1935   // while a transition is happening
1936   // var transitionValues = []; 1936   // var transitionValues = [];
1937   // for ( var prop in style ) { 1937   // for ( var prop in style ) {
1938   //   // dash-ify camelCased properties like WebkitTransition 1938   //   // dash-ify camelCased properties like WebkitTransition
1939   //   prop = vendorProperties[ prop ] || prop; 1939   //   prop = vendorProperties[ prop ] || prop;
1940   //   transitionValues.push( toDashedAll( prop ) ); 1940   //   transitionValues.push( toDashedAll( prop ) );
1941   // } 1941   // }
1942   // enable transition styles 1942   // enable transition styles
1943   this.css({ 1943   this.css({
1944     transitionProperty: transitionProps, 1944     transitionProperty: transitionProps,
1945     transitionDuration: this.layout.options.transitionDuration 1945     transitionDuration: this.layout.options.transitionDuration
1946   }); 1946   });
1947   // listen for transition end event 1947   // listen for transition end event
1948   this.element.addEventListener( transitionEndEvent, this, false ); 1948   this.element.addEventListener( transitionEndEvent, this, false );
1949 }; 1949 };
1950  1950 
1951 Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ]; 1951 Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
1952  1952 
1953 // ----- events ----- // 1953 // ----- events ----- //
1954  1954 
1955 Item.prototype.onwebkitTransitionEnd = function( event ) { 1955 Item.prototype.onwebkitTransitionEnd = function( event ) {
1956   this.ontransitionend( event ); 1956   this.ontransitionend( event );
1957 }; 1957 };
1958  1958 
1959 Item.prototype.onotransitionend = function( event ) { 1959 Item.prototype.onotransitionend = function( event ) {
1960   this.ontransitionend( event ); 1960   this.ontransitionend( event );
1961 }; 1961 };
1962  1962 
1963 // properties that I munge to make my life easier 1963 // properties that I munge to make my life easier
1964 var dashedVendorProperties = { 1964 var dashedVendorProperties = {
1965   '-webkit-transform': 'transform', 1965   '-webkit-transform': 'transform',
1966   '-moz-transform': 'transform', 1966   '-moz-transform': 'transform',
1967   '-o-transform': 'transform' 1967   '-o-transform': 'transform'
1968 }; 1968 };
1969  1969 
1970 Item.prototype.ontransitionend = function( event ) { 1970 Item.prototype.ontransitionend = function( event ) {
1971   // disregard bubbled events from children 1971   // disregard bubbled events from children
1972   if ( event.target !== this.element ) { 1972   if ( event.target !== this.element ) {
1973     return; 1973     return;
1974   } 1974   }
1975   var _transition = this._transn; 1975   var _transition = this._transn;
1976   // get property name of transitioned property, convert to prefix-free 1976   // get property name of transitioned property, convert to prefix-free
1977   var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; 1977   var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
1978  1978 
1979   // remove property that has completed transitioning 1979   // remove property that has completed transitioning
1980   delete _transition.ingProperties[ propertyName ]; 1980   delete _transition.ingProperties[ propertyName ];
1981   // check if any properties are still transitioning 1981   // check if any properties are still transitioning
1982   if ( isEmptyObj( _transition.ingProperties ) ) { 1982   if ( isEmptyObj( _transition.ingProperties ) ) {
1983     // all properties have completed transitioning 1983     // all properties have completed transitioning
1984     this.disableTransition(); 1984     this.disableTransition();
1985   } 1985   }
1986   // clean style 1986   // clean style
1987   if ( propertyName in _transition.clean ) { 1987   if ( propertyName in _transition.clean ) {
1988     // clean up style 1988     // clean up style
1989     this.element.style[ event.propertyName ] = ''; 1989     this.element.style[ event.propertyName ] = '';
1990     delete _transition.clean[ propertyName ]; 1990     delete _transition.clean[ propertyName ];
1991   } 1991   }
1992   // trigger onTransitionEnd callback 1992   // trigger onTransitionEnd callback
1993   if ( propertyName in _transition.onEnd ) { 1993   if ( propertyName in _transition.onEnd ) {
1994     var onTransitionEnd = _transition.onEnd[ propertyName ]; 1994     var onTransitionEnd = _transition.onEnd[ propertyName ];
1995     onTransitionEnd.call( this ); 1995     onTransitionEnd.call( this );
1996     delete _transition.onEnd[ propertyName ]; 1996     delete _transition.onEnd[ propertyName ];
1997   } 1997   }
1998  1998 
1999   this.emitEvent( 'transitionEnd', [ this ] ); 1999   this.emitEvent( 'transitionEnd', [ this ] );
2000 }; 2000 };
2001  2001 
2002 Item.prototype.disableTransition = function() { 2002 Item.prototype.disableTransition = function() {
2003   this.removeTransitionStyles(); 2003   this.removeTransitionStyles();
2004   this.element.removeEventListener( transitionEndEvent, this, false ); 2004   this.element.removeEventListener( transitionEndEvent, this, false );
2005   this.isTransitioning = false; 2005   this.isTransitioning = false;
2006 }; 2006 };
2007  2007 
2008 /** 2008 /**
2009  * removes style property from element 2009  * removes style property from element
2010  * @param {Object} style 2010  * @param {Object} style
2011 **/ 2011 **/
2012 Item.prototype._removeStyles = function( style ) { 2012 Item.prototype._removeStyles = function( style ) {
2013   // clean up transition styles 2013   // clean up transition styles
2014   var cleanStyle = {}; 2014   var cleanStyle = {};
2015   for ( var prop in style ) { 2015   for ( var prop in style ) {
2016     cleanStyle[ prop ] = ''; 2016     cleanStyle[ prop ] = '';
2017   } 2017   }
2018   this.css( cleanStyle ); 2018   this.css( cleanStyle );
2019 }; 2019 };
2020  2020 
2021 var cleanTransitionStyle = { 2021 var cleanTransitionStyle = {
2022   transitionProperty: '', 2022   transitionProperty: '',
2023   transitionDuration: '' 2023   transitionDuration: ''
2024 }; 2024 };
2025  2025 
2026 Item.prototype.removeTransitionStyles = function() { 2026 Item.prototype.removeTransitionStyles = function() {
2027   // remove transition 2027   // remove transition
2028   this.css( cleanTransitionStyle ); 2028   this.css( cleanTransitionStyle );
2029 }; 2029 };
2030  2030 
2031 // ----- show/hide/remove ----- // 2031 // ----- show/hide/remove ----- //
2032  2032 
2033 // remove element from DOM 2033 // remove element from DOM
2034 Item.prototype.removeElem = function() { 2034 Item.prototype.removeElem = function() {
2035   this.element.parentNode.removeChild( this.element ); 2035   this.element.parentNode.removeChild( this.element );
2036   // remove display: none 2036   // remove display: none
2037   this.css({ display: '' }); 2037   this.css({ display: '' });
2038   this.emitEvent( 'remove', [ this ] ); 2038   this.emitEvent( 'remove', [ this ] );
2039 }; 2039 };
2040  2040 
2041 Item.prototype.remove = function() { 2041 Item.prototype.remove = function() {
2042   // just remove element if no transition support or no transition 2042   // just remove element if no transition support or no transition
2043   if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { 2043   if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
2044     this.removeElem(); 2044     this.removeElem();
2045     return; 2045     return;
2046   } 2046   }
2047  2047 
2048   // start transition 2048   // start transition
2049   var _this = this; 2049   var _this = this;
2050   this.once( 'transitionEnd', function() { 2050   this.once( 'transitionEnd', function() {
2051     _this.removeElem(); 2051     _this.removeElem();
2052   }); 2052   });
2053   this.hide(); 2053   this.hide();
2054 }; 2054 };
2055  2055 
2056 Item.prototype.reveal = function() { 2056 Item.prototype.reveal = function() {
2057   delete this.isHidden; 2057   delete this.isHidden;
2058   // remove display: none 2058   // remove display: none
2059   this.css({ display: '' }); 2059   this.css({ display: '' });
2060  2060 
2061   var options = this.layout.options; 2061   var options = this.layout.options;
2062  2062 
2063   var onTransitionEnd = {}; 2063   var onTransitionEnd = {};
2064   var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); 2064   var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
2065   onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd; 2065   onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
2066  2066 
2067   this.transition({ 2067   this.transition({
2068     from: options.hiddenStyle, 2068     from: options.hiddenStyle,
2069     to: options.visibleStyle, 2069     to: options.visibleStyle,
2070     isCleaning: true, 2070     isCleaning: true,
2071     onTransitionEnd: onTransitionEnd 2071     onTransitionEnd: onTransitionEnd
2072   }); 2072   });
2073 }; 2073 };
2074  2074 
2075 Item.prototype.onRevealTransitionEnd = function() { 2075 Item.prototype.onRevealTransitionEnd = function() {
2076   // check if still visible 2076   // check if still visible
2077   // during transition, item may have been hidden 2077   // during transition, item may have been hidden
2078   if ( !this.isHidden ) { 2078   if ( !this.isHidden ) {
2079     this.emitEvent('reveal'); 2079     this.emitEvent('reveal');
2080   } 2080   }
2081 }; 2081 };
2082  2082 
2083 /** 2083 /**
2084  * get style property use for hide/reveal transition end 2084  * get style property use for hide/reveal transition end
2085  * @param {String} styleProperty - hiddenStyle/visibleStyle 2085  * @param {String} styleProperty - hiddenStyle/visibleStyle
2086  * @returns {String} 2086  * @returns {String}
2087  */ 2087  */
2088 Item.prototype.getHideRevealTransitionEndProperty = function( styleProperty ) { 2088 Item.prototype.getHideRevealTransitionEndProperty = function( styleProperty ) {
2089   var optionStyle = this.layout.options[ styleProperty ]; 2089   var optionStyle = this.layout.options[ styleProperty ];
2090   // use opacity 2090   // use opacity
2091   if ( optionStyle.opacity ) { 2091   if ( optionStyle.opacity ) {
2092     return 'opacity'; 2092     return 'opacity';
2093   } 2093   }
2094   // get first property 2094   // get first property
2095   for ( var prop in optionStyle ) { 2095   for ( var prop in optionStyle ) {
2096     return prop; 2096     return prop;
2097   } 2097   }
2098 }; 2098 };
2099  2099 
2100 Item.prototype.hide = function() { 2100 Item.prototype.hide = function() {
2101   // set flag 2101   // set flag
2102   this.isHidden = true; 2102   this.isHidden = true;
2103   // remove display: none 2103   // remove display: none
2104   this.css({ display: '' }); 2104   this.css({ display: '' });
2105  2105 
2106   var options = this.layout.options; 2106   var options = this.layout.options;
2107  2107 
2108   var onTransitionEnd = {}; 2108   var onTransitionEnd = {};
2109   var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); 2109   var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
2110   onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd; 2110   onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
2111  2111 
2112   this.transition({ 2112   this.transition({
2113     from: options.visibleStyle, 2113     from: options.visibleStyle,
2114     to: options.hiddenStyle, 2114     to: options.hiddenStyle,
2115     // keep hidden stuff hidden 2115     // keep hidden stuff hidden
2116     isCleaning: true, 2116     isCleaning: true,
2117     onTransitionEnd: onTransitionEnd 2117     onTransitionEnd: onTransitionEnd
2118   }); 2118   });
2119 }; 2119 };
2120  2120 
2121 Item.prototype.onHideTransitionEnd = function() { 2121 Item.prototype.onHideTransitionEnd = function() {
2122   // check if still hidden 2122   // check if still hidden
2123   // during transition, item may have been un-hidden 2123   // during transition, item may have been un-hidden
2124   if ( this.isHidden ) { 2124   if ( this.isHidden ) {
2125     this.css({ display: 'none' }); 2125     this.css({ display: 'none' });
2126     this.emitEvent('hide'); 2126     this.emitEvent('hide');
2127   } 2127   }
2128 }; 2128 };
2129  2129 
2130 Item.prototype.destroy = function() { 2130 Item.prototype.destroy = function() {
2131   this.css({ 2131   this.css({
2132     position: '', 2132     position: '',
2133     left: '', 2133     left: '',
2134     right: '', 2134     right: '',
2135     top: '', 2135     top: '',
2136     bottom: '', 2136     bottom: '',
2137     transition: '', 2137     transition: '',
2138     transform: '' 2138     transform: ''
2139   }); 2139   });
2140 }; 2140 };
2141  2141 
2142 return Item; 2142 return Item;
2143  2143 
2144 })); 2144 }));
2145  2145 
2146 /*! 2146 /*!
2147  * Outlayer v1.4.2 2147  * Outlayer v1.4.2
2148  * the brains and guts of a layout library 2148  * the brains and guts of a layout library
2149  * MIT license 2149  * MIT license
2150  */ 2150  */
2151  2151 
2152 ( function( window, factory ) { 2152 ( function( window, factory ) {
2153    2153   
2154   // universal module definition 2154   // universal module definition
2155  2155 
2156   if ( typeof define == 'function' && define.amd ) { 2156   if ( typeof define == 'function' && define.amd ) {
2157     // AMD 2157     // AMD
2158     define( 'outlayer/outlayer',[ 2158     define( 'outlayer/outlayer',[
2159         'eventie/eventie', 2159         'eventie/eventie',
2160         'eventEmitter/EventEmitter', 2160         'eventEmitter/EventEmitter',
2161         'get-size/get-size', 2161         'get-size/get-size',
2162         'fizzy-ui-utils/utils', 2162         'fizzy-ui-utils/utils',
2163         './item' 2163         './item'
2164       ], 2164       ],
2165       function( eventie, EventEmitter, getSize, utils, Item ) { 2165       function( eventie, EventEmitter, getSize, utils, Item ) {
2166         return factory( window, eventie, EventEmitter, getSize, utils, Item); 2166         return factory( window, eventie, EventEmitter, getSize, utils, Item);
2167       } 2167       }
2168     ); 2168     );
2169   } else if ( typeof exports == 'object' ) { 2169   } else if ( typeof exports == 'object' ) {
2170     // CommonJS 2170     // CommonJS
2171     module.exports = factory( 2171     module.exports = factory(
2172       window, 2172       window,
2173       require('eventie'), 2173       require('eventie'),
2174       require('wolfy87-eventemitter'), 2174       require('wolfy87-eventemitter'),
2175       require('get-size'), 2175       require('get-size'),
2176       require('fizzy-ui-utils'), 2176       require('fizzy-ui-utils'),
2177       require('./item') 2177       require('./item')
2178     ); 2178     );
2179   } else { 2179   } else {
2180     // browser global 2180     // browser global
2181     window.Outlayer = factory( 2181     window.Outlayer = factory(
2182       window, 2182       window,
2183       window.eventie, 2183       window.eventie,
2184       window.EventEmitter, 2184       window.EventEmitter,
2185       window.getSize, 2185       window.getSize,
2186       window.fizzyUIUtils, 2186       window.fizzyUIUtils,
2187       window.Outlayer.Item 2187       window.Outlayer.Item
2188     ); 2188     );
2189   } 2189   }
2190  2190 
2191 }( window, function factory( window, eventie, EventEmitter, getSize, utils, Item ) { 2191 }( window, function factory( window, eventie, EventEmitter, getSize, utils, Item ) {
2192  2192 
2193  2193 
2194 // ----- vars ----- // 2194 // ----- vars ----- //
2195  2195 
2196 var console = window.console; 2196 var console = window.console;
2197 var jQuery = window.jQuery; 2197 var jQuery = window.jQuery;
2198 var noop = function() {}; 2198 var noop = function() {};
2199  2199 
2200 // -------------------------- Outlayer -------------------------- // 2200 // -------------------------- Outlayer -------------------------- //
2201  2201 
2202 // globally unique identifiers 2202 // globally unique identifiers
2203 var GUID = 0; 2203 var GUID = 0;
2204 // internal store of all Outlayer intances 2204 // internal store of all Outlayer intances
2205 var instances = {}; 2205 var instances = {};
2206  2206 
2207  2207 
2208 /** 2208 /**
2209  * @param {Element, String} element 2209  * @param {Element, String} element
2210  * @param {Object} options 2210  * @param {Object} options
2211  * @constructor 2211  * @constructor
2212  */ 2212  */
2213 function Outlayer( element, options ) { 2213 function Outlayer( element, options ) {
2214   var queryElement = utils.getQueryElement( element ); 2214   var queryElement = utils.getQueryElement( element );
2215   if ( !queryElement ) { 2215   if ( !queryElement ) {
2216     if ( console ) { 2216     if ( console ) {
2217       console.error( 'Bad element for ' + this.constructor.namespace + 2217       console.error( 'Bad element for ' + this.constructor.namespace +
2218         ': ' + ( queryElement || element ) ); 2218         ': ' + ( queryElement || element ) );
2219     } 2219     }
2220     return; 2220     return;
2221   } 2221   }
2222   this.element = queryElement; 2222   this.element = queryElement;
2223   // add jQuery 2223   // add jQuery
2224   if ( jQuery ) { 2224   if ( jQuery ) {
2225     this.$element = jQuery( this.element ); 2225     this.$element = jQuery( this.element );
2226   } 2226   }
2227  2227 
2228   // options 2228   // options
2229   this.options = utils.extend( {}, this.constructor.defaults ); 2229   this.options = utils.extend( {}, this.constructor.defaults );
2230   this.option( options ); 2230   this.option( options );
2231  2231 
2232   // add id for Outlayer.getFromElement 2232   // add id for Outlayer.getFromElement
2233   var id = ++GUID; 2233   var id = ++GUID;
2234   this.element.outlayerGUID = id; // expando 2234   this.element.outlayerGUID = id; // expando
2235   instances[ id ] = this; // associate via id 2235   instances[ id ] = this; // associate via id
2236  2236 
2237   // kick it off 2237   // kick it off
2238   this._create(); 2238   this._create();
2239  2239 
2240   if ( this.options.isInitLayout ) { 2240   if ( this.options.isInitLayout ) {
2241     this.layout(); 2241     this.layout();
2242   } 2242   }
2243 } 2243 }
2244  2244 
2245 // settings are for internal use only 2245 // settings are for internal use only
2246 Outlayer.namespace = 'outlayer'; 2246 Outlayer.namespace = 'outlayer';
2247 Outlayer.Item = Item; 2247 Outlayer.Item = Item;
2248  2248 
2249 // default options 2249 // default options
2250 Outlayer.defaults = { 2250 Outlayer.defaults = {
2251   containerStyle: { 2251   containerStyle: {
2252     position: 'relative' 2252     position: 'relative'
2253   }, 2253   },
2254   isInitLayout: true, 2254   isInitLayout: true,
2255   isOriginLeft: true, 2255   isOriginLeft: true,
2256   isOriginTop: true, 2256   isOriginTop: true,
2257   isResizeBound: true, 2257   isResizeBound: true,
2258   isResizingContainer: true, 2258   isResizingContainer: true,
2259   // item options 2259   // item options
2260   transitionDuration: '0.4s', 2260   transitionDuration: '0.4s',
2261   hiddenStyle: { 2261   hiddenStyle: {
2262     opacity: 0, 2262     opacity: 0,
2263     transform: 'scale(0.001)' 2263     transform: 'scale(0.001)'
2264   }, 2264   },
2265   visibleStyle: { 2265   visibleStyle: {
2266     opacity: 1, 2266     opacity: 1,
2267     transform: 'scale(1)' 2267     transform: 'scale(1)'
2268   } 2268   }
2269 }; 2269 };
2270  2270 
2271 // inherit EventEmitter 2271 // inherit EventEmitter
2272 utils.extend( Outlayer.prototype, EventEmitter.prototype ); 2272 utils.extend( Outlayer.prototype, EventEmitter.prototype );
2273  2273 
2274 /** 2274 /**
2275  * set options 2275  * set options
2276  * @param {Object} opts 2276  * @param {Object} opts
2277  */ 2277  */
2278 Outlayer.prototype.option = function( opts ) { 2278 Outlayer.prototype.option = function( opts ) {
2279   utils.extend( this.options, opts ); 2279   utils.extend( this.options, opts );
2280 }; 2280 };
2281  2281 
2282 Outlayer.prototype._create = function() { 2282 Outlayer.prototype._create = function() {
2283   // get items from children 2283   // get items from children
2284   this.reloadItems(); 2284   this.reloadItems();
2285   // elements that affect layout, but are not laid out 2285   // elements that affect layout, but are not laid out
2286   this.stamps = []; 2286   this.stamps = [];
2287   this.stamp( this.options.stamp ); 2287   this.stamp( this.options.stamp );
2288   // set container style 2288   // set container style
2289   utils.extend( this.element.style, this.options.containerStyle ); 2289   utils.extend( this.element.style, this.options.containerStyle );
2290  2290 
2291   // bind resize method 2291   // bind resize method
2292   if ( this.options.isResizeBound ) { 2292   if ( this.options.isResizeBound ) {
2293     this.bindResize(); 2293     this.bindResize();
2294   } 2294   }
2295 }; 2295 };
2296  2296 
2297 // goes through all children again and gets bricks in proper order 2297 // goes through all children again and gets bricks in proper order
2298 Outlayer.prototype.reloadItems = function() { 2298 Outlayer.prototype.reloadItems = function() {
2299   // collection of item elements 2299   // collection of item elements
2300   this.items = this._itemize( this.element.children ); 2300   this.items = this._itemize( this.element.children );
2301 }; 2301 };
2302  2302 
2303  2303 
2304 /** 2304 /**
2305  * turn elements into Outlayer.Items to be used in layout 2305  * turn elements into Outlayer.Items to be used in layout
2306  * @param {Array or NodeList or HTMLElement} elems 2306  * @param {Array or NodeList or HTMLElement} elems
2307  * @returns {Array} items - collection of new Outlayer Items 2307  * @returns {Array} items - collection of new Outlayer Items
2308  */ 2308  */
2309 Outlayer.prototype._itemize = function( elems ) { 2309 Outlayer.prototype._itemize = function( elems ) {
2310  2310 
2311   var itemElems = this._filterFindItemElements( elems ); 2311   var itemElems = this._filterFindItemElements( elems );
2312   var Item = this.constructor.Item; 2312   var Item = this.constructor.Item;
2313  2313 
2314   // create new Outlayer Items for collection 2314   // create new Outlayer Items for collection
2315   var items = []; 2315   var items = [];
2316   for ( var i=0, len = itemElems.length; i < len; i++ ) { 2316   for ( var i=0, len = itemElems.length; i < len; i++ ) {
2317     var elem = itemElems[i]; 2317     var elem = itemElems[i];
2318     var item = new Item( elem, this ); 2318     var item = new Item( elem, this );
2319     items.push( item ); 2319     items.push( item );
2320   } 2320   }
2321  2321 
2322   return items; 2322   return items;
2323 }; 2323 };
2324  2324 
2325 /** 2325 /**
2326  * get item elements to be used in layout 2326  * get item elements to be used in layout
2327  * @param {Array or NodeList or HTMLElement} elems 2327  * @param {Array or NodeList or HTMLElement} elems
2328  * @returns {Array} items - item elements 2328  * @returns {Array} items - item elements
2329  */ 2329  */
2330 Outlayer.prototype._filterFindItemElements = function( elems ) { 2330 Outlayer.prototype._filterFindItemElements = function( elems ) {
2331   return utils.filterFindElements( elems, this.options.itemSelector ); 2331   return utils.filterFindElements( elems, this.options.itemSelector );
2332 }; 2332 };
2333  2333 
2334 /** 2334 /**
2335  * getter method for getting item elements 2335  * getter method for getting item elements
2336  * @returns {Array} elems - collection of item elements 2336  * @returns {Array} elems - collection of item elements
2337  */ 2337  */
2338 Outlayer.prototype.getItemElements = function() { 2338 Outlayer.prototype.getItemElements = function() {
2339   var elems = []; 2339   var elems = [];
2340   for ( var i=0, len = this.items.length; i < len; i++ ) { 2340   for ( var i=0, len = this.items.length; i < len; i++ ) {
2341     elems.push( this.items[i].element ); 2341     elems.push( this.items[i].element );
2342   } 2342   }
2343   return elems; 2343   return elems;
2344 }; 2344 };
2345  2345 
2346 // ----- init & layout ----- // 2346 // ----- init & layout ----- //
2347  2347 
2348 /** 2348 /**
2349  * lays out all items 2349  * lays out all items
2350  */ 2350  */
2351 Outlayer.prototype.layout = function() { 2351 Outlayer.prototype.layout = function() {
2352   this._resetLayout(); 2352   this._resetLayout();
2353   this._manageStamps(); 2353   this._manageStamps();
2354  2354 
2355   // don't animate first layout 2355   // don't animate first layout
2356   var isInstant = this.options.isLayoutInstant !== undefined ? 2356   var isInstant = this.options.isLayoutInstant !== undefined ?
2357     this.options.isLayoutInstant : !this._isLayoutInited; 2357     this.options.isLayoutInstant : !this._isLayoutInited;
2358   this.layoutItems( this.items, isInstant ); 2358   this.layoutItems( this.items, isInstant );
2359  2359 
2360   // flag for initalized 2360   // flag for initalized
2361   this._isLayoutInited = true; 2361   this._isLayoutInited = true;
2362 }; 2362 };
2363  2363 
2364 // _init is alias for layout 2364 // _init is alias for layout
2365 Outlayer.prototype._init = Outlayer.prototype.layout; 2365 Outlayer.prototype._init = Outlayer.prototype.layout;
2366  2366 
2367 /** 2367 /**
2368  * logic before any new layout 2368  * logic before any new layout
2369  */ 2369  */
2370 Outlayer.prototype._resetLayout = function() { 2370 Outlayer.prototype._resetLayout = function() {
2371   this.getSize(); 2371   this.getSize();
2372 }; 2372 };
2373  2373 
2374  2374 
2375 Outlayer.prototype.getSize = function() { 2375 Outlayer.prototype.getSize = function() {
2376   this.size = getSize( this.element ); 2376   this.size = getSize( this.element );
2377 }; 2377 };
2378  2378 
2379 /** 2379 /**
2380  * get measurement from option, for columnWidth, rowHeight, gutter 2380  * get measurement from option, for columnWidth, rowHeight, gutter
2381  * if option is String -> get element from selector string, & get size of element 2381  * if option is String -> get element from selector string, & get size of element
2382  * if option is Element -> get size of element 2382  * if option is Element -> get size of element
2383  * else use option as a number 2383  * else use option as a number
2384  * 2384  *
2385  * @param {String} measurement 2385  * @param {String} measurement
2386  * @param {String} size - width or height 2386  * @param {String} size - width or height
2387  * @private 2387  * @private
2388  */ 2388  */
2389 Outlayer.prototype._getMeasurement = function( measurement, size ) { 2389 Outlayer.prototype._getMeasurement = function( measurement, size ) {
2390   var option = this.options[ measurement ]; 2390   var option = this.options[ measurement ];
2391   var elem; 2391   var elem;
2392   if ( !option ) { 2392   if ( !option ) {
2393     // default to 0 2393     // default to 0
2394     this[ measurement ] = 0; 2394     this[ measurement ] = 0;
2395   } else { 2395   } else {
2396     // use option as an element 2396     // use option as an element
2397     if ( typeof option === 'string' ) { 2397     if ( typeof option === 'string' ) {
2398       elem = this.element.querySelector( option ); 2398       elem = this.element.querySelector( option );
2399     } else if ( utils.isElement( option ) ) { 2399     } else if ( utils.isElement( option ) ) {
2400       elem = option; 2400       elem = option;
2401     } 2401     }
2402     // use size of element, if element 2402     // use size of element, if element
2403     this[ measurement ] = elem ? getSize( elem )[ size ] : option; 2403     this[ measurement ] = elem ? getSize( elem )[ size ] : option;
2404   } 2404   }
2405 }; 2405 };
2406  2406 
2407 /** 2407 /**
2408  * layout a collection of item elements 2408  * layout a collection of item elements
2409  * @api public 2409  * @api public
2410  */ 2410  */
2411 Outlayer.prototype.layoutItems = function( items, isInstant ) { 2411 Outlayer.prototype.layoutItems = function( items, isInstant ) {
2412   items = this._getItemsForLayout( items ); 2412   items = this._getItemsForLayout( items );
2413  2413 
2414   this._layoutItems( items, isInstant ); 2414   this._layoutItems( items, isInstant );
2415  2415 
2416   this._postLayout(); 2416   this._postLayout();
2417 }; 2417 };
2418  2418 
2419 /** 2419 /**
2420  * get the items to be laid out 2420  * get the items to be laid out
2421  * you may want to skip over some items 2421  * you may want to skip over some items
2422  * @param {Array} items 2422  * @param {Array} items
2423  * @returns {Array} items 2423  * @returns {Array} items
2424  */ 2424  */
2425 Outlayer.prototype._getItemsForLayout = function( items ) { 2425 Outlayer.prototype._getItemsForLayout = function( items ) {
2426   var layoutItems = []; 2426   var layoutItems = [];
2427   for ( var i=0, len = items.length; i < len; i++ ) { 2427   for ( var i=0, len = items.length; i < len; i++ ) {
2428     var item = items[i]; 2428     var item = items[i];
2429     if ( !item.isIgnored ) { 2429     if ( !item.isIgnored ) {
2430       layoutItems.push( item ); 2430       layoutItems.push( item );
2431     } 2431     }
2432   } 2432   }
2433   return layoutItems; 2433   return layoutItems;
2434 }; 2434 };
2435  2435 
2436 /** 2436 /**
2437  * layout items 2437  * layout items
2438  * @param {Array} items 2438  * @param {Array} items
2439  * @param {Boolean} isInstant 2439  * @param {Boolean} isInstant
2440  */ 2440  */
2441 Outlayer.prototype._layoutItems = function( items, isInstant ) { 2441 Outlayer.prototype._layoutItems = function( items, isInstant ) {
2442   this._emitCompleteOnItems( 'layout', items ); 2442   this._emitCompleteOnItems( 'layout', items );
2443  2443 
2444   if ( !items || !items.length ) { 2444   if ( !items || !items.length ) {
2445     // no items, emit event with empty array 2445     // no items, emit event with empty array
2446     return; 2446     return;
2447   } 2447   }
2448  2448 
2449   var queue = []; 2449   var queue = [];
2450  2450 
2451   for ( var i=0, len = items.length; i < len; i++ ) { 2451   for ( var i=0, len = items.length; i < len; i++ ) {
2452     var item = items[i]; 2452     var item = items[i];
2453     // get x/y object from method 2453     // get x/y object from method
2454     var position = this._getItemLayoutPosition( item ); 2454     var position = this._getItemLayoutPosition( item );
2455     // enqueue 2455     // enqueue
2456     position.item = item; 2456     position.item = item;
2457     position.isInstant = isInstant || item.isLayoutInstant; 2457     position.isInstant = isInstant || item.isLayoutInstant;
2458     queue.push( position ); 2458     queue.push( position );
2459   } 2459   }
2460  2460 
2461   this._processLayoutQueue( queue ); 2461   this._processLayoutQueue( queue );
2462 }; 2462 };
2463  2463 
2464 /** 2464 /**
2465  * get item layout position 2465  * get item layout position
2466  * @param {Outlayer.Item} item 2466  * @param {Outlayer.Item} item
2467  * @returns {Object} x and y position 2467  * @returns {Object} x and y position
2468  */ 2468  */
2469 Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) { 2469 Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
2470   return { 2470   return {
2471     x: 0, 2471     x: 0,
2472     y: 0 2472     y: 0
2473   }; 2473   };
2474 }; 2474 };
2475  2475 
2476 /** 2476 /**
2477  * iterate over array and position each item 2477  * iterate over array and position each item
2478  * Reason being - separating this logic prevents 'layout invalidation' 2478  * Reason being - separating this logic prevents 'layout invalidation'
2479  * thx @paul_irish 2479  * thx @paul_irish
2480  * @param {Array} queue 2480  * @param {Array} queue
2481  */ 2481  */
2482 Outlayer.prototype._processLayoutQueue = function( queue ) { 2482 Outlayer.prototype._processLayoutQueue = function( queue ) {
2483   for ( var i=0, len = queue.length; i < len; i++ ) { 2483   for ( var i=0, len = queue.length; i < len; i++ ) {
2484     var obj = queue[i]; 2484     var obj = queue[i];
2485     this._positionItem( obj.item, obj.x, obj.y, obj.isInstant ); 2485     this._positionItem( obj.item, obj.x, obj.y, obj.isInstant );
2486   } 2486   }
2487 }; 2487 };
2488  2488 
2489 /** 2489 /**
2490  * Sets position of item in DOM 2490  * Sets position of item in DOM
2491  * @param {Outlayer.Item} item 2491  * @param {Outlayer.Item} item
2492  * @param {Number} x - horizontal position 2492  * @param {Number} x - horizontal position
2493  * @param {Number} y - vertical position 2493  * @param {Number} y - vertical position
2494  * @param {Boolean} isInstant - disables transitions 2494  * @param {Boolean} isInstant - disables transitions
2495  */ 2495  */
2496 Outlayer.prototype._positionItem = function( item, x, y, isInstant ) { 2496 Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
2497   if ( isInstant ) { 2497   if ( isInstant ) {
2498     // if not transition, just set CSS 2498     // if not transition, just set CSS
2499     item.goTo( x, y ); 2499     item.goTo( x, y );
2500   } else { 2500   } else {
2501     item.moveTo( x, y ); 2501     item.moveTo( x, y );
2502   } 2502   }
2503 }; 2503 };
2504  2504 
2505 /** 2505 /**
2506  * Any logic you want to do after each layout, 2506  * Any logic you want to do after each layout,
2507  * i.e. size the container 2507  * i.e. size the container
2508  */ 2508  */
2509 Outlayer.prototype._postLayout = function() { 2509 Outlayer.prototype._postLayout = function() {
2510   this.resizeContainer(); 2510   this.resizeContainer();
2511 }; 2511 };
2512  2512 
2513 Outlayer.prototype.resizeContainer = function() { 2513 Outlayer.prototype.resizeContainer = function() {
2514   if ( !this.options.isResizingContainer ) { 2514   if ( !this.options.isResizingContainer ) {
2515     return; 2515     return;
2516   } 2516   }
2517   var size = this._getContainerSize(); 2517   var size = this._getContainerSize();
2518   if ( size ) { 2518   if ( size ) {
2519     this._setContainerMeasure( size.width, true ); 2519     this._setContainerMeasure( size.width, true );
2520     this._setContainerMeasure( size.height, false ); 2520     this._setContainerMeasure( size.height, false );
2521   } 2521   }
2522 }; 2522 };
2523  2523 
2524 /** 2524 /**
2525  * Sets width or height of container if returned 2525  * Sets width or height of container if returned
2526  * @returns {Object} size 2526  * @returns {Object} size
2527  *   @param {Number} width 2527  *   @param {Number} width
2528  *   @param {Number} height 2528  *   @param {Number} height
2529  */ 2529  */
2530 Outlayer.prototype._getContainerSize = noop; 2530 Outlayer.prototype._getContainerSize = noop;
2531  2531 
2532 /** 2532 /**
2533  * @param {Number} measure - size of width or height 2533  * @param {Number} measure - size of width or height
2534  * @param {Boolean} isWidth 2534  * @param {Boolean} isWidth
2535  */ 2535  */
2536 Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) { 2536 Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
2537   if ( measure === undefined ) { 2537   if ( measure === undefined ) {
2538     return; 2538     return;
2539   } 2539   }
2540  2540 
2541   var elemSize = this.size; 2541   var elemSize = this.size;
2542   // add padding and border width if border box 2542   // add padding and border width if border box
2543   if ( elemSize.isBorderBox ) { 2543   if ( elemSize.isBorderBox ) {
2544     measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + 2544     measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
2545       elemSize.borderLeftWidth + elemSize.borderRightWidth : 2545       elemSize.borderLeftWidth + elemSize.borderRightWidth :
2546       elemSize.paddingBottom + elemSize.paddingTop + 2546       elemSize.paddingBottom + elemSize.paddingTop +
2547       elemSize.borderTopWidth + elemSize.borderBottomWidth; 2547       elemSize.borderTopWidth + elemSize.borderBottomWidth;
2548   } 2548   }
2549  2549 
2550   measure = Math.max( measure, 0 ); 2550   measure = Math.max( measure, 0 );
2551   this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; 2551   this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
2552 }; 2552 };
2553  2553 
2554 /** 2554 /**
2555  * emit eventComplete on a collection of items events 2555  * emit eventComplete on a collection of items events
2556  * @param {String} eventName 2556  * @param {String} eventName
2557  * @param {Array} items - Outlayer.Items 2557  * @param {Array} items - Outlayer.Items
2558  */ 2558  */
2559 Outlayer.prototype._emitCompleteOnItems = function( eventName, items ) { 2559 Outlayer.prototype._emitCompleteOnItems = function( eventName, items ) {
2560   var _this = this; 2560   var _this = this;
2561   function onComplete() { 2561   function onComplete() {
2562     _this.dispatchEvent( eventName + 'Complete', null, [ items ] ); 2562     _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
2563   } 2563   }
2564  2564 
2565   var count = items.length; 2565   var count = items.length;
2566   if ( !items || !count ) { 2566   if ( !items || !count ) {
2567     onComplete(); 2567     onComplete();
2568     return; 2568     return;
2569   } 2569   }
2570  2570 
2571   var doneCount = 0; 2571   var doneCount = 0;
2572   function tick() { 2572   function tick() {
2573     doneCount++; 2573     doneCount++;
2574     if ( doneCount === count ) { 2574     if ( doneCount === count ) {
2575       onComplete(); 2575       onComplete();
2576     } 2576     }
2577   } 2577   }
2578  2578 
2579   // bind callback 2579   // bind callback
2580   for ( var i=0, len = items.length; i < len; i++ ) { 2580   for ( var i=0, len = items.length; i < len; i++ ) {
2581     var item = items[i]; 2581     var item = items[i];
2582     item.once( eventName, tick ); 2582     item.once( eventName, tick );
2583   } 2583   }
2584 }; 2584 };
2585  2585 
2586 /** 2586 /**
2587  * emits events via eventEmitter and jQuery events 2587  * emits events via eventEmitter and jQuery events
2588  * @param {String} type - name of event 2588  * @param {String} type - name of event
2589  * @param {Event} event - original event 2589  * @param {Event} event - original event
2590  * @param {Array} args - extra arguments 2590  * @param {Array} args - extra arguments
2591  */ 2591  */
2592 Outlayer.prototype.dispatchEvent = function( type, event, args ) { 2592 Outlayer.prototype.dispatchEvent = function( type, event, args ) {
2593   // add original event to arguments 2593   // add original event to arguments
2594   var emitArgs = event ? [ event ].concat( args ) : args; 2594   var emitArgs = event ? [ event ].concat( args ) : args;
2595   this.emitEvent( type, emitArgs ); 2595   this.emitEvent( type, emitArgs );
2596  2596 
2597   if ( jQuery ) { 2597   if ( jQuery ) {
2598     // set this.$element 2598     // set this.$element
2599     this.$element = this.$element || jQuery( this.element ); 2599     this.$element = this.$element || jQuery( this.element );
2600     if ( event ) { 2600     if ( event ) {
2601       // create jQuery event 2601       // create jQuery event
2602       var $event = jQuery.Event( event ); 2602       var $event = jQuery.Event( event );
2603       $event.type = type; 2603       $event.type = type;
2604       this.$element.trigger( $event, args ); 2604       this.$element.trigger( $event, args );
2605     } else { 2605     } else {
2606       // just trigger with type if no event available 2606       // just trigger with type if no event available
2607       this.$element.trigger( type, args ); 2607       this.$element.trigger( type, args );
2608     } 2608     }
2609   } 2609   }
2610 }; 2610 };
2611  2611 
2612 // -------------------------- ignore & stamps -------------------------- // 2612 // -------------------------- ignore & stamps -------------------------- //
2613  2613 
2614  2614 
2615 /** 2615 /**
2616  * keep item in collection, but do not lay it out 2616  * keep item in collection, but do not lay it out
2617  * ignored items do not get skipped in layout 2617  * ignored items do not get skipped in layout
2618  * @param {Element} elem 2618  * @param {Element} elem
2619  */ 2619  */
2620 Outlayer.prototype.ignore = function( elem ) { 2620 Outlayer.prototype.ignore = function( elem ) {
2621   var item = this.getItem( elem ); 2621   var item = this.getItem( elem );
2622   if ( item ) { 2622   if ( item ) {
2623     item.isIgnored = true; 2623     item.isIgnored = true;
2624   } 2624   }
2625 }; 2625 };
2626  2626 
2627 /** 2627 /**
2628  * return item to layout collection 2628  * return item to layout collection
2629  * @param {Element} elem 2629  * @param {Element} elem
2630  */ 2630  */
2631 Outlayer.prototype.unignore = function( elem ) { 2631 Outlayer.prototype.unignore = function( elem ) {
2632   var item = this.getItem( elem ); 2632   var item = this.getItem( elem );
2633   if ( item ) { 2633   if ( item ) {
2634     delete item.isIgnored; 2634     delete item.isIgnored;
2635   } 2635   }
2636 }; 2636 };
2637  2637 
2638 /** 2638 /**
2639  * adds elements to stamps 2639  * adds elements to stamps
2640  * @param {NodeList, Array, Element, or String} elems 2640  * @param {NodeList, Array, Element, or String} elems
2641  */ 2641  */
2642 Outlayer.prototype.stamp = function( elems ) { 2642 Outlayer.prototype.stamp = function( elems ) {
2643   elems = this._find( elems ); 2643   elems = this._find( elems );
2644   if ( !elems ) { 2644   if ( !elems ) {
2645     return; 2645     return;
2646   } 2646   }
2647  2647 
2648   this.stamps = this.stamps.concat( elems ); 2648   this.stamps = this.stamps.concat( elems );
2649   // ignore 2649   // ignore
2650   for ( var i=0, len = elems.length; i < len; i++ ) { 2650   for ( var i=0, len = elems.length; i < len; i++ ) {
2651     var elem = elems[i]; 2651     var elem = elems[i];
2652     this.ignore( elem ); 2652     this.ignore( elem );
2653   } 2653   }
2654 }; 2654 };
2655  2655 
2656 /** 2656 /**
2657  * removes elements to stamps 2657  * removes elements to stamps
2658  * @param {NodeList, Array, or Element} elems 2658  * @param {NodeList, Array, or Element} elems
2659  */ 2659  */
2660 Outlayer.prototype.unstamp = function( elems ) { 2660 Outlayer.prototype.unstamp = function( elems ) {
2661   elems = this._find( elems ); 2661   elems = this._find( elems );
2662   if ( !elems ){ 2662   if ( !elems ){
2663     return; 2663     return;
2664   } 2664   }
2665  2665 
2666   for ( var i=0, len = elems.length; i < len; i++ ) { 2666   for ( var i=0, len = elems.length; i < len; i++ ) {
2667     var elem = elems[i]; 2667     var elem = elems[i];
2668     // filter out removed stamp elements 2668     // filter out removed stamp elements
2669     utils.removeFrom( this.stamps, elem ); 2669     utils.removeFrom( this.stamps, elem );
2670     this.unignore( elem ); 2670     this.unignore( elem );
2671   } 2671   }
2672  2672 
2673 }; 2673 };
2674  2674 
2675 /** 2675 /**
2676  * finds child elements 2676  * finds child elements
2677  * @param {NodeList, Array, Element, or String} elems 2677  * @param {NodeList, Array, Element, or String} elems
2678  * @returns {Array} elems 2678  * @returns {Array} elems
2679  */ 2679  */
2680 Outlayer.prototype._find = function( elems ) { 2680 Outlayer.prototype._find = function( elems ) {
2681   if ( !elems ) { 2681   if ( !elems ) {
2682     return; 2682     return;
2683   } 2683   }
2684   // if string, use argument as selector string 2684   // if string, use argument as selector string
2685   if ( typeof elems === 'string' ) { 2685   if ( typeof elems === 'string' ) {
2686     elems = this.element.querySelectorAll( elems ); 2686     elems = this.element.querySelectorAll( elems );
2687   } 2687   }
2688   elems = utils.makeArray( elems ); 2688   elems = utils.makeArray( elems );
2689   return elems; 2689   return elems;
2690 }; 2690 };
2691  2691 
2692 Outlayer.prototype._manageStamps = function() { 2692 Outlayer.prototype._manageStamps = function() {
2693   if ( !this.stamps || !this.stamps.length ) { 2693   if ( !this.stamps || !this.stamps.length ) {
2694     return; 2694     return;
2695   } 2695   }
2696  2696 
2697   this._getBoundingRect(); 2697   this._getBoundingRect();
2698  2698 
2699   for ( var i=0, len = this.stamps.length; i < len; i++ ) { 2699   for ( var i=0, len = this.stamps.length; i < len; i++ ) {
2700     var stamp = this.stamps[i]; 2700     var stamp = this.stamps[i];
2701     this._manageStamp( stamp ); 2701     this._manageStamp( stamp );
2702   } 2702   }
2703 }; 2703 };
2704  2704 
2705 // update boundingLeft / Top 2705 // update boundingLeft / Top
2706 Outlayer.prototype._getBoundingRect = function() { 2706 Outlayer.prototype._getBoundingRect = function() {
2707   // get bounding rect for container element 2707   // get bounding rect for container element
2708   var boundingRect = this.element.getBoundingClientRect(); 2708   var boundingRect = this.element.getBoundingClientRect();
2709   var size = this.size; 2709   var size = this.size;
2710   this._boundingRect = { 2710   this._boundingRect = {
2711     left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, 2711     left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
2712     top: boundingRect.top + size.paddingTop + size.borderTopWidth, 2712     top: boundingRect.top + size.paddingTop + size.borderTopWidth,
2713     right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), 2713     right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
2714     bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) 2714     bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
2715   }; 2715   };
2716 }; 2716 };
2717  2717 
2718 /** 2718 /**
2719  * @param {Element} stamp 2719  * @param {Element} stamp
2720 **/ 2720 **/
2721 Outlayer.prototype._manageStamp = noop; 2721 Outlayer.prototype._manageStamp = noop;
2722  2722 
2723 /** 2723 /**
2724  * get x/y position of element relative to container element 2724  * get x/y position of element relative to container element
2725  * @param {Element} elem 2725  * @param {Element} elem
2726  * @returns {Object} offset - has left, top, right, bottom 2726  * @returns {Object} offset - has left, top, right, bottom
2727  */ 2727  */
2728 Outlayer.prototype._getElementOffset = function( elem ) { 2728 Outlayer.prototype._getElementOffset = function( elem ) {
2729   var boundingRect = elem.getBoundingClientRect(); 2729   var boundingRect = elem.getBoundingClientRect();
2730   var thisRect = this._boundingRect; 2730   var thisRect = this._boundingRect;
2731   var size = getSize( elem ); 2731   var size = getSize( elem );
2732   var offset = { 2732   var offset = {
2733     left: boundingRect.left - thisRect.left - size.marginLeft, 2733     left: boundingRect.left - thisRect.left - size.marginLeft,
2734     top: boundingRect.top - thisRect.top - size.marginTop, 2734     top: boundingRect.top - thisRect.top - size.marginTop,
2735     right: thisRect.right - boundingRect.right - size.marginRight, 2735     right: thisRect.right - boundingRect.right - size.marginRight,
2736     bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom 2736     bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
2737   }; 2737   };
2738   return offset; 2738   return offset;
2739 }; 2739 };
2740  2740 
2741 // -------------------------- resize -------------------------- // 2741 // -------------------------- resize -------------------------- //
2742  2742 
2743 // enable event handlers for listeners 2743 // enable event handlers for listeners
2744 // i.e. resize -> onresize 2744 // i.e. resize -> onresize
2745 Outlayer.prototype.handleEvent = function( event ) { 2745 Outlayer.prototype.handleEvent = function( event ) {
2746   var method = 'on' + event.type; 2746   var method = 'on' + event.type;
2747   if ( this[ method ] ) { 2747   if ( this[ method ] ) {
2748     this[ method ]( event ); 2748     this[ method ]( event );
2749   } 2749   }
2750 }; 2750 };
2751  2751 
2752 /** 2752 /**
2753  * Bind layout to window resizing 2753  * Bind layout to window resizing
2754  */ 2754  */
2755 Outlayer.prototype.bindResize = function() { 2755 Outlayer.prototype.bindResize = function() {
2756   // bind just one listener 2756   // bind just one listener
2757   if ( this.isResizeBound ) { 2757   if ( this.isResizeBound ) {
2758     return; 2758     return;
2759   } 2759   }
2760   window.eventie.bind( window, 'resize', this ); 2760   window.eventie.bind( window, 'resize', this );
2761   this.isResizeBound = true; 2761   this.isResizeBound = true;
2762 }; 2762 };
2763  2763 
2764 /** 2764 /**
2765  * Unbind layout to window resizing 2765  * Unbind layout to window resizing
2766  */ 2766  */
2767 Outlayer.prototype.unbindResize = function() { 2767 Outlayer.prototype.unbindResize = function() {
2768   if ( this.isResizeBound ) { 2768   if ( this.isResizeBound ) {
2769     window.eventie.unbind( window, 'resize', this ); 2769     window.eventie.unbind( window, 'resize', this );
2770   } 2770   }
2771   this.isResizeBound = false; 2771   this.isResizeBound = false;
2772 }; 2772 };
2773  2773 
2774 // original debounce by John Hann 2774 // original debounce by John Hann
2775 // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/ 2775 // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
2776  2776 
2777 // this fires every resize 2777 // this fires every resize
2778 Outlayer.prototype.onresize = function() { 2778 Outlayer.prototype.onresize = function() {
2779   if ( this.resizeTimeout ) { 2779   if ( this.resizeTimeout ) {
2780     clearTimeout( this.resizeTimeout ); 2780     clearTimeout( this.resizeTimeout );
2781   } 2781   }
2782  2782 
2783   var _this = this; 2783   var _this = this;
2784   function delayed() { 2784   function delayed() {
2785     _this.resize(); 2785     _this.resize();
2786     delete _this.resizeTimeout; 2786     delete _this.resizeTimeout;
2787   } 2787   }
2788  2788 
2789   this.resizeTimeout = setTimeout( delayed, 100 ); 2789   this.resizeTimeout = setTimeout( delayed, 100 );
2790 }; 2790 };
2791  2791 
2792 // debounced, layout on resize 2792 // debounced, layout on resize
2793 Outlayer.prototype.resize = function() { 2793 Outlayer.prototype.resize = function() {
2794   // don't trigger if size did not change 2794   // don't trigger if size did not change
2795   // or if resize was unbound. See #9 2795   // or if resize was unbound. See #9
2796   if ( !this.isResizeBound || !this.needsResizeLayout() ) { 2796   if ( !this.isResizeBound || !this.needsResizeLayout() ) {
2797     return; 2797     return;
2798   } 2798   }
2799  2799 
2800   this.layout(); 2800   this.layout();
2801 }; 2801 };
2802  2802 
2803 /** 2803 /**
2804  * check if layout is needed post layout 2804  * check if layout is needed post layout
2805  * @returns Boolean 2805  * @returns Boolean
2806  */ 2806  */
2807 Outlayer.prototype.needsResizeLayout = function() { 2807 Outlayer.prototype.needsResizeLayout = function() {
2808   var size = getSize( this.element ); 2808   var size = getSize( this.element );
2809   // check that this.size and size are there 2809   // check that this.size and size are there
2810   // IE8 triggers resize on body size change, so they might not be 2810   // IE8 triggers resize on body size change, so they might not be
2811   var hasSizes = this.size && size; 2811   var hasSizes = this.size && size;
2812   return hasSizes && size.innerWidth !== this.size.innerWidth; 2812   return hasSizes && size.innerWidth !== this.size.innerWidth;
2813 }; 2813 };
2814  2814 
2815 // -------------------------- methods -------------------------- // 2815 // -------------------------- methods -------------------------- //
2816  2816 
2817 /** 2817 /**
2818  * add items to Outlayer instance 2818  * add items to Outlayer instance
2819  * @param {Array or NodeList or Element} elems 2819  * @param {Array or NodeList or Element} elems
2820  * @returns {Array} items - Outlayer.Items 2820  * @returns {Array} items - Outlayer.Items
2821 **/ 2821 **/
2822 Outlayer.prototype.addItems = function( elems ) { 2822 Outlayer.prototype.addItems = function( elems ) {
2823   var items = this._itemize( elems ); 2823   var items = this._itemize( elems );
2824   // add items to collection 2824   // add items to collection
2825   if ( items.length ) { 2825   if ( items.length ) {
2826     this.items = this.items.concat( items ); 2826     this.items = this.items.concat( items );
2827   } 2827   }
2828   return items; 2828   return items;
2829 }; 2829 };
2830  2830 
2831 /** 2831 /**
2832  * Layout newly-appended item elements 2832  * Layout newly-appended item elements
2833  * @param {Array or NodeList or Element} elems 2833  * @param {Array or NodeList or Element} elems
2834  */ 2834  */
2835 Outlayer.prototype.appended = function( elems ) { 2835 Outlayer.prototype.appended = function( elems ) {
2836   var items = this.addItems( elems ); 2836   var items = this.addItems( elems );
2837   if ( !items.length ) { 2837   if ( !items.length ) {
2838     return; 2838     return;
2839   } 2839   }
2840   // layout and reveal just the new items 2840   // layout and reveal just the new items
2841   this.layoutItems( items, true ); 2841   this.layoutItems( items, true );
2842   this.reveal( items ); 2842   this.reveal( items );
2843 }; 2843 };
2844  2844 
2845 /** 2845 /**
2846  * Layout prepended elements 2846  * Layout prepended elements
2847  * @param {Array or NodeList or Element} elems 2847  * @param {Array or NodeList or Element} elems
2848  */ 2848  */
2849 Outlayer.prototype.prepended = function( elems ) { 2849 Outlayer.prototype.prepended = function( elems ) {
2850   var items = this._itemize( elems ); 2850   var items = this._itemize( elems );
2851   if ( !items.length ) { 2851   if ( !items.length ) {
2852     return; 2852     return;
2853   } 2853   }
2854   // add items to beginning of collection 2854   // add items to beginning of collection
2855   var previousItems = this.items.slice(0); 2855   var previousItems = this.items.slice(0);
2856   this.items = items.concat( previousItems ); 2856   this.items = items.concat( previousItems );
2857   // start new layout 2857   // start new layout
2858   this._resetLayout(); 2858   this._resetLayout();
2859   this._manageStamps(); 2859   this._manageStamps();
2860   // layout new stuff without transition 2860   // layout new stuff without transition
2861   this.layoutItems( items, true ); 2861   this.layoutItems( items, true );
2862   this.reveal( items ); 2862   this.reveal( items );
2863   // layout previous items 2863   // layout previous items
2864   this.layoutItems( previousItems ); 2864   this.layoutItems( previousItems );
2865 }; 2865 };
2866  2866 
2867 /** 2867 /**
2868  * reveal a collection of items 2868  * reveal a collection of items
2869  * @param {Array of Outlayer.Items} items 2869  * @param {Array of Outlayer.Items} items
2870  */ 2870  */
2871 Outlayer.prototype.reveal = function( items ) { 2871 Outlayer.prototype.reveal = function( items ) {
2872   this._emitCompleteOnItems( 'reveal', items ); 2872   this._emitCompleteOnItems( 'reveal', items );
2873  2873 
2874   var len = items && items.length; 2874   var len = items && items.length;
2875   for ( var i=0; len && i < len; i++ ) { 2875   for ( var i=0; len && i < len; i++ ) {
2876     var item = items[i]; 2876     var item = items[i];
2877     item.reveal(); 2877     item.reveal();
2878   } 2878   }
2879 }; 2879 };
2880  2880 
2881 /** 2881 /**
2882  * hide a collection of items 2882  * hide a collection of items
2883  * @param {Array of Outlayer.Items} items 2883  * @param {Array of Outlayer.Items} items
2884  */ 2884  */
2885 Outlayer.prototype.hide = function( items ) { 2885 Outlayer.prototype.hide = function( items ) {
2886   this._emitCompleteOnItems( 'hide', items ); 2886   this._emitCompleteOnItems( 'hide', items );
2887  2887 
2888   var len = items && items.length; 2888   var len = items && items.length;
2889   for ( var i=0; len && i < len; i++ ) { 2889   for ( var i=0; len && i < len; i++ ) {
2890     var item = items[i]; 2890     var item = items[i];
2891     item.hide(); 2891     item.hide();
2892   } 2892   }
2893 }; 2893 };
2894  2894 
2895 /** 2895 /**
2896  * reveal item elements 2896  * reveal item elements
2897  * @param {Array}, {Element}, {NodeList} items 2897  * @param {Array}, {Element}, {NodeList} items
2898  */ 2898  */
2899 Outlayer.prototype.revealItemElements = function( elems ) { 2899 Outlayer.prototype.revealItemElements = function( elems ) {
2900   var items = this.getItems( elems ); 2900   var items = this.getItems( elems );
2901   this.reveal( items ); 2901   this.reveal( items );
2902 }; 2902 };
2903  2903 
2904 /** 2904 /**
2905  * hide item elements 2905  * hide item elements
2906  * @param {Array}, {Element}, {NodeList} items 2906  * @param {Array}, {Element}, {NodeList} items
2907  */ 2907  */
2908 Outlayer.prototype.hideItemElements = function( elems ) { 2908 Outlayer.prototype.hideItemElements = function( elems ) {
2909   var items = this.getItems( elems ); 2909   var items = this.getItems( elems );
2910   this.hide( items ); 2910   this.hide( items );
2911 }; 2911 };
2912  2912 
2913 /** 2913 /**
2914  * get Outlayer.Item, given an Element 2914  * get Outlayer.Item, given an Element
2915  * @param {Element} elem 2915  * @param {Element} elem
2916  * @param {Function} callback 2916  * @param {Function} callback
2917  * @returns {Outlayer.Item} item 2917  * @returns {Outlayer.Item} item
2918  */ 2918  */
2919 Outlayer.prototype.getItem = function( elem ) { 2919 Outlayer.prototype.getItem = function( elem ) {
2920   // loop through items to get the one that matches 2920   // loop through items to get the one that matches
2921   for ( var i=0, len = this.items.length; i < len; i++ ) { 2921   for ( var i=0, len = this.items.length; i < len; i++ ) {
2922     var item = this.items[i]; 2922     var item = this.items[i];
2923     if ( item.element === elem ) { 2923     if ( item.element === elem ) {
2924       // return item 2924       // return item
2925       return item; 2925       return item;
2926     } 2926     }
2927   } 2927   }
2928 }; 2928 };
2929  2929 
2930 /** 2930 /**
2931  * get collection of Outlayer.Items, given Elements 2931  * get collection of Outlayer.Items, given Elements
2932  * @param {Array} elems 2932  * @param {Array} elems
2933  * @returns {Array} items - Outlayer.Items 2933  * @returns {Array} items - Outlayer.Items
2934  */ 2934  */
2935 Outlayer.prototype.getItems = function( elems ) { 2935 Outlayer.prototype.getItems = function( elems ) {
2936   elems = utils.makeArray( elems ); 2936   elems = utils.makeArray( elems );
2937   var items = []; 2937   var items = [];
2938   for ( var i=0, len = elems.length; i < len; i++ ) { 2938   for ( var i=0, len = elems.length; i < len; i++ ) {
2939     var elem = elems[i]; 2939     var elem = elems[i];
2940     var item = this.getItem( elem ); 2940     var item = this.getItem( elem );
2941     if ( item ) { 2941     if ( item ) {
2942       items.push( item ); 2942       items.push( item );
2943     } 2943     }
2944   } 2944   }
2945  2945 
2946   return items; 2946   return items;
2947 }; 2947 };
2948  2948 
2949 /** 2949 /**
2950  * remove element(s) from instance and DOM 2950  * remove element(s) from instance and DOM
2951  * @param {Array or NodeList or Element} elems 2951  * @param {Array or NodeList or Element} elems
2952  */ 2952  */
2953 Outlayer.prototype.remove = function( elems ) { 2953 Outlayer.prototype.remove = function( elems ) {
2954   var removeItems = this.getItems( elems ); 2954   var removeItems = this.getItems( elems );
2955  2955 
2956   this._emitCompleteOnItems( 'remove', removeItems ); 2956   this._emitCompleteOnItems( 'remove', removeItems );
2957  2957 
2958   // bail if no items to remove 2958   // bail if no items to remove
2959   if ( !removeItems || !removeItems.length ) { 2959   if ( !removeItems || !removeItems.length ) {
2960     return; 2960     return;
2961   } 2961   }
2962  2962 
2963   for ( var i=0, len = removeItems.length; i < len; i++ ) { 2963   for ( var i=0, len = removeItems.length; i < len; i++ ) {
2964     var item = removeItems[i]; 2964     var item = removeItems[i];
2965     item.remove(); 2965     item.remove();
2966     // remove item from collection 2966     // remove item from collection
2967     utils.removeFrom( this.items, item ); 2967     utils.removeFrom( this.items, item );
2968   } 2968   }
2969 }; 2969 };
2970  2970 
2971 // ----- destroy ----- // 2971 // ----- destroy ----- //
2972  2972 
2973 // remove and disable Outlayer instance 2973 // remove and disable Outlayer instance
2974 Outlayer.prototype.destroy = function() { 2974 Outlayer.prototype.destroy = function() {
2975   // clean up dynamic styles 2975   // clean up dynamic styles
2976   var style = this.element.style; 2976   var style = this.element.style;
2977   style.height = ''; 2977   style.height = '';
2978   style.position = ''; 2978   style.position = '';
2979   style.width = ''; 2979   style.width = '';
2980   // destroy items 2980   // destroy items
2981   for ( var i=0, len = this.items.length; i < len; i++ ) { 2981   for ( var i=0, len = this.items.length; i < len; i++ ) {
2982     var item = this.items[i]; 2982     var item = this.items[i];
2983     item.destroy(); 2983     item.destroy();
2984   } 2984   }
2985  2985 
2986   this.unbindResize(); 2986   this.unbindResize();
2987  2987 
2988   var id = this.element.outlayerGUID; 2988   var id = this.element.outlayerGUID;
2989   delete instances[ id ]; // remove reference to instance by id 2989   delete instances[ id ]; // remove reference to instance by id
2990   delete this.element.outlayerGUID; 2990   delete this.element.outlayerGUID;
2991   // remove data for jQuery 2991   // remove data for jQuery
2992   if ( jQuery ) { 2992   if ( jQuery ) {
2993     jQuery.removeData( this.element, this.constructor.namespace ); 2993     jQuery.removeData( this.element, this.constructor.namespace );
2994   } 2994   }
2995  2995 
2996 }; 2996 };
2997  2997 
2998 // -------------------------- data -------------------------- // 2998 // -------------------------- data -------------------------- //
2999  2999 
3000 /** 3000 /**
3001  * get Outlayer instance from element 3001  * get Outlayer instance from element
3002  * @param {Element} elem 3002  * @param {Element} elem
3003  * @returns {Outlayer} 3003  * @returns {Outlayer}
3004  */ 3004  */
3005 Outlayer.data = function( elem ) { 3005 Outlayer.data = function( elem ) {
3006   elem = utils.getQueryElement( elem ); 3006   elem = utils.getQueryElement( elem );
3007   var id = elem && elem.outlayerGUID; 3007   var id = elem && elem.outlayerGUID;
3008   return id && instances[ id ]; 3008   return id && instances[ id ];
3009 }; 3009 };
3010  3010 
3011  3011 
3012 // -------------------------- create Outlayer class -------------------------- // 3012 // -------------------------- create Outlayer class -------------------------- //
3013  3013 
3014 /** 3014 /**
3015  * create a layout class 3015  * create a layout class
3016  * @param {String} namespace 3016  * @param {String} namespace
3017  */ 3017  */
3018 Outlayer.create = function( namespace, options ) { 3018 Outlayer.create = function( namespace, options ) {
3019   // sub-class Outlayer 3019   // sub-class Outlayer
3020   function Layout() { 3020   function Layout() {
3021     Outlayer.apply( this, arguments ); 3021     Outlayer.apply( this, arguments );
3022   } 3022   }
3023   // inherit Outlayer prototype, use Object.create if there 3023   // inherit Outlayer prototype, use Object.create if there
3024   if ( Object.create ) { 3024   if ( Object.create ) {
3025     Layout.prototype = Object.create( Outlayer.prototype ); 3025     Layout.prototype = Object.create( Outlayer.prototype );
3026   } else { 3026   } else {
3027     utils.extend( Layout.prototype, Outlayer.prototype ); 3027     utils.extend( Layout.prototype, Outlayer.prototype );
3028   } 3028   }
3029   // set contructor, used for namespace and Item 3029   // set contructor, used for namespace and Item
3030   Layout.prototype.constructor = Layout; 3030   Layout.prototype.constructor = Layout;
3031  3031 
3032   Layout.defaults = utils.extend( {}, Outlayer.defaults ); 3032   Layout.defaults = utils.extend( {}, Outlayer.defaults );
3033   // apply new options 3033   // apply new options
3034   utils.extend( Layout.defaults, options ); 3034   utils.extend( Layout.defaults, options );
3035   // keep prototype.settings for backwards compatibility (Packery v1.2.0) 3035   // keep prototype.settings for backwards compatibility (Packery v1.2.0)
3036   Layout.prototype.settings = {}; 3036   Layout.prototype.settings = {};
3037  3037 
3038   Layout.namespace = namespace; 3038   Layout.namespace = namespace;
3039  3039 
3040   Layout.data = Outlayer.data; 3040   Layout.data = Outlayer.data;
3041  3041 
3042   // sub-class Item 3042   // sub-class Item
3043   Layout.Item = function LayoutItem() { 3043   Layout.Item = function LayoutItem() {
3044     Item.apply( this, arguments ); 3044     Item.apply( this, arguments );
3045   }; 3045   };
3046  3046 
3047   Layout.Item.prototype = new Item(); 3047   Layout.Item.prototype = new Item();
3048  3048 
3049   // -------------------------- declarative -------------------------- // 3049   // -------------------------- declarative -------------------------- //
3050  3050 
3051   utils.htmlInit( Layout, namespace ); 3051   utils.htmlInit( Layout, namespace );
3052  3052 
3053   // -------------------------- jQuery bridge -------------------------- // 3053   // -------------------------- jQuery bridge -------------------------- //
3054  3054 
3055   // make into jQuery plugin 3055   // make into jQuery plugin
3056   if ( jQuery && jQuery.bridget ) { 3056   if ( jQuery && jQuery.bridget ) {
3057     jQuery.bridget( namespace, Layout ); 3057     jQuery.bridget( namespace, Layout );
3058   } 3058   }
3059  3059 
3060   return Layout; 3060   return Layout;
3061 }; 3061 };
3062  3062 
3063 // ----- fin ----- // 3063 // ----- fin ----- //
3064  3064 
3065 // back in global 3065 // back in global
3066 Outlayer.Item = Item; 3066 Outlayer.Item = Item;
3067  3067 
3068 return Outlayer; 3068 return Outlayer;
3069  3069 
3070 })); 3070 }));
3071  3071 
3072  3072 
3073 /** 3073 /**
3074  * Rect 3074  * Rect
3075  * low-level utility class for basic geometry 3075  * low-level utility class for basic geometry
3076  */ 3076  */
3077  3077 
3078 ( function( window, factory ) { 3078 ( function( window, factory ) {
3079    3079   
3080   // universal module definition 3080   // universal module definition
3081   if ( typeof define == 'function' && define.amd ) { 3081   if ( typeof define == 'function' && define.amd ) {
3082     // AMD 3082     // AMD
3083     define( 'packery/js/rect',factory ); 3083     define( 'packery/js/rect',factory );
3084   } else if ( typeof exports == 'object' ) { 3084   } else if ( typeof exports == 'object' ) {
3085     // CommonJS 3085     // CommonJS
3086     module.exports = factory(); 3086     module.exports = factory();
3087   } else { 3087   } else {
3088     // browser global 3088     // browser global
3089     window.Packery = window.Packery || {}; 3089     window.Packery = window.Packery || {};
3090     window.Packery.Rect = factory(); 3090     window.Packery.Rect = factory();
3091   } 3091   }
3092  3092 
3093 }( window, function factory() { 3093 }( window, function factory() {
3094  3094 
3095  3095 
3096 // -------------------------- Packery -------------------------- // 3096 // -------------------------- Packery -------------------------- //
3097  3097 
3098 // global namespace 3098 // global namespace
3099 var Packery = window.Packery = function() {}; 3099 var Packery = window.Packery = function() {};
3100  3100 
3101 // -------------------------- Rect -------------------------- // 3101 // -------------------------- Rect -------------------------- //
3102  3102 
3103 function Rect( props ) { 3103 function Rect( props ) {
3104   // extend properties from defaults 3104   // extend properties from defaults
3105   for ( var prop in Rect.defaults ) { 3105   for ( var prop in Rect.defaults ) {
3106     this[ prop ] = Rect.defaults[ prop ]; 3106     this[ prop ] = Rect.defaults[ prop ];
3107   } 3107   }
3108  3108 
3109   for ( prop in props ) { 3109   for ( prop in props ) {
3110     this[ prop ] = props[ prop ]; 3110     this[ prop ] = props[ prop ];
3111   } 3111   }
3112  3112 
3113 } 3113 }
3114  3114 
3115 // make available 3115 // make available
3116 Packery.Rect = Rect; 3116 Packery.Rect = Rect;
3117  3117 
3118 Rect.defaults = { 3118 Rect.defaults = {
3119   x: 0, 3119   x: 0,
3120   y: 0, 3120   y: 0,
3121   width: 0, 3121   width: 0,
3122   height: 0 3122   height: 0
3123 }; 3123 };
3124  3124 
3125 /** 3125 /**
3126  * Determines whether or not this rectangle wholly encloses another rectangle or point. 3126  * Determines whether or not this rectangle wholly encloses another rectangle or point.
3127  * @param {Rect} rect 3127  * @param {Rect} rect
3128  * @returns {Boolean} 3128  * @returns {Boolean}
3129 **/ 3129 **/
3130 Rect.prototype.contains = function( rect ) { 3130 Rect.prototype.contains = function( rect ) {
3131   // points don't have width or height 3131   // points don't have width or height
3132   var otherWidth = rect.width || 0; 3132   var otherWidth = rect.width || 0;
3133   var otherHeight = rect.height || 0; 3133   var otherHeight = rect.height || 0;
3134   return this.x <= rect.x && 3134   return this.x <= rect.x &&
3135     this.y <= rect.y && 3135     this.y <= rect.y &&
3136     this.x + this.width >= rect.x + otherWidth && 3136     this.x + this.width >= rect.x + otherWidth &&
3137     this.y + this.height >= rect.y + otherHeight; 3137     this.y + this.height >= rect.y + otherHeight;
3138 }; 3138 };
3139  3139 
3140 /** 3140 /**
3141  * Determines whether or not the rectangle intersects with another. 3141  * Determines whether or not the rectangle intersects with another.
3142  * @param {Rect} rect 3142  * @param {Rect} rect
3143  * @returns {Boolean} 3143  * @returns {Boolean}
3144 **/ 3144 **/
3145 Rect.prototype.overlaps = function( rect ) { 3145 Rect.prototype.overlaps = function( rect ) {
3146   var thisRight = this.x + this.width; 3146   var thisRight = this.x + this.width;
3147   var thisBottom = this.y + this.height; 3147   var thisBottom = this.y + this.height;
3148   var rectRight = rect.x + rect.width; 3148   var rectRight = rect.x + rect.width;
3149   var rectBottom = rect.y + rect.height; 3149   var rectBottom = rect.y + rect.height;
3150  3150 
3151   // http://stackoverflow.com/a/306332 3151   // http://stackoverflow.com/a/306332
3152   return this.x < rectRight && 3152   return this.x < rectRight &&
3153     thisRight > rect.x && 3153     thisRight > rect.x &&
3154     this.y < rectBottom && 3154     this.y < rectBottom &&
3155     thisBottom > rect.y; 3155     thisBottom > rect.y;
3156 }; 3156 };
3157  3157 
3158 /** 3158 /**
3159  * @param {Rect} rect - the overlapping rect 3159  * @param {Rect} rect - the overlapping rect
3160  * @returns {Array} freeRects - rects representing the area around the rect 3160  * @returns {Array} freeRects - rects representing the area around the rect
3161 **/ 3161 **/
3162 Rect.prototype.getMaximalFreeRects = function( rect ) { 3162 Rect.prototype.getMaximalFreeRects = function( rect ) {
3163  3163 
3164   // if no intersection, return false 3164   // if no intersection, return false
3165   if ( !this.overlaps( rect ) ) { 3165   if ( !this.overlaps( rect ) ) {
3166     return false; 3166     return false;
3167   } 3167   }
3168  3168 
3169   var freeRects = []; 3169   var freeRects = [];
3170   var freeRect; 3170   var freeRect;
3171  3171 
3172   var thisRight = this.x + this.width; 3172   var thisRight = this.x + this.width;
3173   var thisBottom = this.y + this.height; 3173   var thisBottom = this.y + this.height;
3174   var rectRight = rect.x + rect.width; 3174   var rectRight = rect.x + rect.width;
3175   var rectBottom = rect.y + rect.height; 3175   var rectBottom = rect.y + rect.height;
3176  3176 
3177   // top 3177   // top
3178   if ( this.y < rect.y ) { 3178   if ( this.y < rect.y ) {
3179     freeRect = new Rect({ 3179     freeRect = new Rect({
3180       x: this.x, 3180       x: this.x,
3181       y: this.y, 3181       y: this.y,
3182       width: this.width, 3182       width: this.width,
3183       height: rect.y - this.y 3183       height: rect.y - this.y
3184     }); 3184     });
3185     freeRects.push( freeRect ); 3185     freeRects.push( freeRect );
3186   } 3186   }
3187  3187 
3188   // right 3188   // right
3189   if ( thisRight > rectRight ) { 3189   if ( thisRight > rectRight ) {
3190     freeRect = new Rect({ 3190     freeRect = new Rect({
3191       x: rectRight, 3191       x: rectRight,
3192       y: this.y, 3192       y: this.y,
3193       width: thisRight - rectRight, 3193       width: thisRight - rectRight,
3194       height: this.height 3194       height: this.height
3195     }); 3195     });
3196     freeRects.push( freeRect ); 3196     freeRects.push( freeRect );
3197   } 3197   }
3198  3198 
3199   // bottom 3199   // bottom
3200   if ( thisBottom > rectBottom ) { 3200   if ( thisBottom > rectBottom ) {
3201     freeRect = new Rect({ 3201     freeRect = new Rect({
3202       x: this.x, 3202       x: this.x,
3203       y: rectBottom, 3203       y: rectBottom,
3204       width: this.width, 3204       width: this.width,
3205       height: thisBottom - rectBottom 3205       height: thisBottom - rectBottom
3206     }); 3206     });
3207     freeRects.push( freeRect ); 3207     freeRects.push( freeRect );
3208   } 3208   }
3209  3209 
3210   // left 3210   // left
3211   if ( this.x < rect.x ) { 3211   if ( this.x < rect.x ) {
3212     freeRect = new Rect({ 3212     freeRect = new Rect({
3213       x: this.x, 3213       x: this.x,
3214       y: this.y, 3214       y: this.y,
3215       width: rect.x - this.x, 3215       width: rect.x - this.x,
3216       height: this.height 3216       height: this.height
3217     }); 3217     });
3218     freeRects.push( freeRect ); 3218     freeRects.push( freeRect );
3219   } 3219   }
3220  3220 
3221   return freeRects; 3221   return freeRects;
3222 }; 3222 };
3223  3223 
3224 Rect.prototype.canFit = function( rect ) { 3224 Rect.prototype.canFit = function( rect ) {
3225   return this.width >= rect.width && this.height >= rect.height; 3225   return this.width >= rect.width && this.height >= rect.height;
3226 }; 3226 };
3227  3227 
3228 return Rect; 3228 return Rect;
3229  3229 
3230 })); 3230 }));
3231  3231 
3232 /** 3232 /**
3233  * Packer 3233  * Packer
3234  * bin-packing algorithm 3234  * bin-packing algorithm
3235  */ 3235  */
3236  3236 
3237 ( function( window, factory ) { 3237 ( function( window, factory ) {
3238    3238   
3239   // universal module definition 3239   // universal module definition
3240   if ( typeof define == 'function' && define.amd ) { 3240   if ( typeof define == 'function' && define.amd ) {
3241     // AMD 3241     // AMD
3242     define( 'packery/js/packer',[ './rect' ], factory ); 3242     define( 'packery/js/packer',[ './rect' ], factory );
3243   } else if ( typeof exports == 'object' ) { 3243   } else if ( typeof exports == 'object' ) {
3244     // CommonJS 3244     // CommonJS
3245     module.exports = factory( 3245     module.exports = factory(
3246       require('./rect') 3246       require('./rect')
3247     ); 3247     );
3248   } else { 3248   } else {
3249     // browser global 3249     // browser global
3250     var Packery = window.Packery = window.Packery || {}; 3250     var Packery = window.Packery = window.Packery || {};
3251     Packery.Packer = factory( Packery.Rect ); 3251     Packery.Packer = factory( Packery.Rect );
3252   } 3252   }
3253  3253 
3254 }( window, function factory( Rect ) { 3254 }( window, function factory( Rect ) {
3255  3255 
3256  3256 
3257 // -------------------------- Packer -------------------------- // 3257 // -------------------------- Packer -------------------------- //
3258  3258 
3259 /** 3259 /**
3260  * @param {Number} width 3260  * @param {Number} width
3261  * @param {Number} height 3261  * @param {Number} height
3262  * @param {String} sortDirection 3262  * @param {String} sortDirection
3263  *   topLeft for vertical, leftTop for horizontal 3263  *   topLeft for vertical, leftTop for horizontal
3264  */ 3264  */
3265 function Packer( width, height, sortDirection ) { 3265 function Packer( width, height, sortDirection ) {
3266   this.width = width || 0; 3266   this.width = width || 0;
3267   this.height = height || 0; 3267   this.height = height || 0;
3268   this.sortDirection = sortDirection || 'downwardLeftToRight'; 3268   this.sortDirection = sortDirection || 'downwardLeftToRight';
3269  3269 
3270   this.reset(); 3270   this.reset();
3271 } 3271 }
3272  3272 
3273 Packer.prototype.reset = function() { 3273 Packer.prototype.reset = function() {
3274   this.spaces = []; 3274   this.spaces = [];
3275   this.newSpaces = []; 3275   this.newSpaces = [];
3276  3276 
3277   var initialSpace = new Rect({ 3277   var initialSpace = new Rect({
3278     x: 0, 3278     x: 0,
3279     y: 0, 3279     y: 0,
3280     width: this.width, 3280     width: this.width,
3281     height: this.height 3281     height: this.height
3282   }); 3282   });
3283  3283 
3284   this.spaces.push( initialSpace ); 3284   this.spaces.push( initialSpace );
3285   // set sorter 3285   // set sorter
3286   this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight; 3286   this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight;
3287 }; 3287 };
3288  3288 
3289 // change x and y of rect to fit with in Packer's available spaces 3289 // change x and y of rect to fit with in Packer's available spaces
3290 Packer.prototype.pack = function( rect ) { 3290 Packer.prototype.pack = function( rect ) {
3291   for ( var i=0, len = this.spaces.length; i < len; i++ ) { 3291   for ( var i=0, len = this.spaces.length; i < len; i++ ) {
3292     var space = this.spaces[i]; 3292     var space = this.spaces[i];
3293     if ( space.canFit( rect ) ) { 3293     if ( space.canFit( rect ) ) {
3294       this.placeInSpace( rect, space ); 3294       this.placeInSpace( rect, space );
3295       break; 3295       break;
3296     } 3296     }
3297   } 3297   }
3298 }; 3298 };
3299  3299 
3300 Packer.prototype.placeInSpace = function( rect, space ) { 3300 Packer.prototype.placeInSpace = function( rect, space ) {
3301   // place rect in space 3301   // place rect in space
3302   rect.x = space.x; 3302   rect.x = space.x;
3303   rect.y = space.y; 3303   rect.y = space.y;
3304  3304 
3305   this.placed( rect ); 3305   this.placed( rect );
3306 }; 3306 };
3307  3307 
3308 // update spaces with placed rect 3308 // update spaces with placed rect
3309 Packer.prototype.placed = function( rect ) { 3309 Packer.prototype.placed = function( rect ) {
3310   // update spaces 3310   // update spaces
3311   var revisedSpaces = []; 3311   var revisedSpaces = [];
3312   for ( var i=0, len = this.spaces.length; i < len; i++ ) { 3312   for ( var i=0, len = this.spaces.length; i < len; i++ ) {
3313     var space = this.spaces[i]; 3313     var space = this.spaces[i];
3314     var newSpaces = space.getMaximalFreeRects( rect ); 3314     var newSpaces = space.getMaximalFreeRects( rect );
3315     // add either the original space or the new spaces to the revised spaces 3315     // add either the original space or the new spaces to the revised spaces
3316     if ( newSpaces ) { 3316     if ( newSpaces ) {
3317       revisedSpaces.push.apply( revisedSpaces, newSpaces ); 3317       revisedSpaces.push.apply( revisedSpaces, newSpaces );
3318     } else { 3318     } else {
3319       revisedSpaces.push( space ); 3319       revisedSpaces.push( space );
3320     } 3320     }
3321   } 3321   }
3322  3322 
3323   this.spaces = revisedSpaces; 3323   this.spaces = revisedSpaces;
3324  3324 
3325   this.mergeSortSpaces(); 3325   this.mergeSortSpaces();
3326 }; 3326 };
3327  3327 
3328 Packer.prototype.mergeSortSpaces = function() { 3328 Packer.prototype.mergeSortSpaces = function() {
3329   // remove redundant spaces 3329   // remove redundant spaces
3330   Packer.mergeRects( this.spaces ); 3330   Packer.mergeRects( this.spaces );
3331   this.spaces.sort( this.sorter ); 3331   this.spaces.sort( this.sorter );
3332 }; 3332 };
3333  3333 
3334 // add a space back 3334 // add a space back
3335 Packer.prototype.addSpace = function( rect ) { 3335 Packer.prototype.addSpace = function( rect ) {
3336   this.spaces.push( rect ); 3336   this.spaces.push( rect );
3337   this.mergeSortSpaces(); 3337   this.mergeSortSpaces();
3338 }; 3338 };
3339  3339 
3340 // -------------------------- utility functions -------------------------- // 3340 // -------------------------- utility functions -------------------------- //
3341  3341 
3342 /** 3342 /**
3343  * Remove redundant rectangle from array of rectangles 3343  * Remove redundant rectangle from array of rectangles
3344  * @param {Array} rects: an array of Rects 3344  * @param {Array} rects: an array of Rects
3345  * @returns {Array} rects: an array of Rects 3345  * @returns {Array} rects: an array of Rects
3346 **/ 3346 **/
3347 Packer.mergeRects = function( rects ) { 3347 Packer.mergeRects = function( rects ) {
3348   for ( var i=0, len = rects.length; i < len; i++ ) { 3348   for ( var i=0, len = rects.length; i < len; i++ ) {
3349     var rect = rects[i]; 3349     var rect = rects[i];
3350     // skip over this rect if it was already removed 3350     // skip over this rect if it was already removed
3351     if ( !rect ) { 3351     if ( !rect ) {
3352       continue; 3352       continue;
3353     } 3353     }
3354     // clone rects we're testing, remove this rect 3354     // clone rects we're testing, remove this rect
3355     var compareRects = rects.slice(0); 3355     var compareRects = rects.slice(0);
3356     // do not compare with self 3356     // do not compare with self
3357     compareRects.splice( i, 1 ); 3357     compareRects.splice( i, 1 );
3358     // compare this rect with others 3358     // compare this rect with others
3359     var removedCount = 0; 3359     var removedCount = 0;
3360     for ( var j=0, jLen = compareRects.length; j < jLen; j++ ) { 3360     for ( var j=0, jLen = compareRects.length; j < jLen; j++ ) {
3361       var compareRect = compareRects[j]; 3361       var compareRect = compareRects[j];
3362       // if this rect contains another, 3362       // if this rect contains another,
3363       // remove that rect from test collection 3363       // remove that rect from test collection
3364       var indexAdjust = i > j ? 0 : 1; 3364       var indexAdjust = i > j ? 0 : 1;
3365       if ( rect.contains( compareRect ) ) { 3365       if ( rect.contains( compareRect ) ) {
3366         // console.log( 'current test rects:' + testRects.length, testRects ); 3366         // console.log( 'current test rects:' + testRects.length, testRects );
3367         // console.log( i, j, indexAdjust, rect, compareRect ); 3367         // console.log( i, j, indexAdjust, rect, compareRect );
3368         rects.splice( j + indexAdjust - removedCount, 1 ); 3368         rects.splice( j + indexAdjust - removedCount, 1 );
3369         removedCount++; 3369         removedCount++;
3370       } 3370       }
3371     } 3371     }
3372   } 3372   }
3373  3373 
3374   return rects; 3374   return rects;
3375 }; 3375 };
3376  3376 
3377  3377 
3378 // -------------------------- sorters -------------------------- // 3378 // -------------------------- sorters -------------------------- //
3379  3379 
3380 // functions for sorting rects in order 3380 // functions for sorting rects in order
3381 var sorters = { 3381 var sorters = {
3382   // top down, then left to right 3382   // top down, then left to right
3383   downwardLeftToRight: function( a, b ) { 3383   downwardLeftToRight: function( a, b ) {
3384     return a.y - b.y || a.x - b.x; 3384     return a.y - b.y || a.x - b.x;
3385   }, 3385   },
3386   // left to right, then top down 3386   // left to right, then top down
3387   rightwardTopToBottom: function( a, b ) { 3387   rightwardTopToBottom: function( a, b ) {
3388     return a.x - b.x || a.y - b.y; 3388     return a.x - b.x || a.y - b.y;
3389   } 3389   }
3390 }; 3390 };
3391  3391 
3392  3392 
3393 // --------------------------  -------------------------- // 3393 // --------------------------  -------------------------- //
3394  3394 
3395 return Packer; 3395 return Packer;
3396  3396 
3397 })); 3397 }));
3398 /** 3398 /**
3399  * Packery Item Element 3399  * Packery Item Element
3400 **/ 3400 **/
3401  3401 
3402 ( function( window, factory ) { 3402 ( function( window, factory ) {
3403    3403   
3404   // universal module definition 3404   // universal module definition
3405  3405 
3406   if ( typeof define == 'function' && define.amd ) { 3406   if ( typeof define == 'function' && define.amd ) {
3407     // AMD 3407     // AMD
3408     define( 'packery/js/item',[ 3408     define( 'packery/js/item',[
3409         'get-style-property/get-style-property', 3409         'get-style-property/get-style-property',
3410         'outlayer/outlayer', 3410         'outlayer/outlayer',
3411         './rect' 3411         './rect'
3412       ], 3412       ],
3413       factory ); 3413       factory );
3414   } else if ( typeof exports == 'object' ) { 3414   } else if ( typeof exports == 'object' ) {
3415     // CommonJS 3415     // CommonJS
3416     module.exports = factory( 3416     module.exports = factory(
3417       require('desandro-get-style-property'), 3417       require('desandro-get-style-property'),
3418       require('outlayer'), 3418       require('outlayer'),
3419       require('./rect') 3419       require('./rect')
3420     ); 3420     );
3421   } else { 3421   } else {
3422     // browser global 3422     // browser global
3423     window.Packery.Item = factory( 3423     window.Packery.Item = factory(
3424       window.getStyleProperty, 3424       window.getStyleProperty,
3425       window.Outlayer, 3425       window.Outlayer,
3426       window.Packery.Rect 3426       window.Packery.Rect
3427     ); 3427     );
3428   } 3428   }
3429  3429 
3430 }( window, function factory( getStyleProperty, Outlayer, Rect ) { 3430 }( window, function factory( getStyleProperty, Outlayer, Rect ) {
3431  3431 
3432  3432 
3433 // -------------------------- Item -------------------------- // 3433 // -------------------------- Item -------------------------- //
3434  3434 
3435 var transformProperty = getStyleProperty('transform'); 3435 var transformProperty = getStyleProperty('transform');
3436  3436 
3437 // sub-class Item 3437 // sub-class Item
3438 var Item = function PackeryItem() { 3438 var Item = function PackeryItem() {
3439   Outlayer.Item.apply( this, arguments ); 3439   Outlayer.Item.apply( this, arguments );
3440 }; 3440 };
3441  3441 
3442 Item.prototype = new Outlayer.Item(); 3442 Item.prototype = new Outlayer.Item();
3443  3443 
3444 var protoCreate = Item.prototype._create; 3444 var protoCreate = Item.prototype._create;
3445 Item.prototype._create = function() { 3445 Item.prototype._create = function() {
3446   // call default _create logic 3446   // call default _create logic
3447   protoCreate.call( this ); 3447   protoCreate.call( this );
3448   this.rect = new Rect(); 3448   this.rect = new Rect();
3449   // rect used for placing, in drag or Packery.fit() 3449   // rect used for placing, in drag or Packery.fit()
3450   this.placeRect = new Rect(); 3450   this.placeRect = new Rect();
3451 }; 3451 };
3452  3452 
3453 // -------------------------- drag -------------------------- // 3453 // -------------------------- drag -------------------------- //
3454  3454 
3455 Item.prototype.dragStart = function() { 3455 Item.prototype.dragStart = function() {
3456   this.getPosition(); 3456   this.getPosition();
3457   this.removeTransitionStyles(); 3457   this.removeTransitionStyles();
3458   // remove transform property from transition 3458   // remove transform property from transition
3459   if ( this.isTransitioning && transformProperty ) { 3459   if ( this.isTransitioning && transformProperty ) {
3460     this.element.style[ transformProperty ] = 'none'; 3460     this.element.style[ transformProperty ] = 'none';
3461   } 3461   }
3462   this.getSize(); 3462   this.getSize();
3463   // create place rect, used for position when dragged then dropped 3463   // create place rect, used for position when dragged then dropped
3464   // or when positioning 3464   // or when positioning
3465   this.isPlacing = true; 3465   this.isPlacing = true;
3466   this.needsPositioning = false; 3466   this.needsPositioning = false;
3467   this.positionPlaceRect( this.position.x, this.position.y ); 3467   this.positionPlaceRect( this.position.x, this.position.y );
3468   this.isTransitioning = false; 3468   this.isTransitioning = false;
3469   this.didDrag = false; 3469   this.didDrag = false;
3470 }; 3470 };
3471  3471 
3472 /** 3472 /**
3473  * handle item when it is dragged 3473  * handle item when it is dragged
3474  * @param {Number} x - horizontal position of dragged item 3474  * @param {Number} x - horizontal position of dragged item
3475  * @param {Number} y - vertical position of dragged item 3475  * @param {Number} y - vertical position of dragged item
3476  */ 3476  */
3477 Item.prototype.dragMove = function( x, y ) { 3477 Item.prototype.dragMove = function( x, y ) {
3478   this.didDrag = true; 3478   this.didDrag = true;
3479   var packerySize = this.layout.size; 3479   var packerySize = this.layout.size;
3480   x -= packerySize.paddingLeft; 3480   x -= packerySize.paddingLeft;
3481   y -= packerySize.paddingTop; 3481   y -= packerySize.paddingTop;
3482   this.positionPlaceRect( x, y ); 3482   this.positionPlaceRect( x, y );
3483 }; 3483 };
3484  3484 
3485 Item.prototype.dragStop = function() { 3485 Item.prototype.dragStop = function() {
3486   this.getPosition(); 3486   this.getPosition();
3487   var isDiffX = this.position.x != this.placeRect.x; 3487   var isDiffX = this.position.x != this.placeRect.x;
3488   var isDiffY = this.position.y != this.placeRect.y; 3488   var isDiffY = this.position.y != this.placeRect.y;
3489   // set post-drag positioning flag 3489   // set post-drag positioning flag
3490   this.needsPositioning = isDiffX || isDiffY; 3490   this.needsPositioning = isDiffX || isDiffY;
3491   // reset flag 3491   // reset flag
3492   this.didDrag = false; 3492   this.didDrag = false;
3493 }; 3493 };
3494  3494 
3495 // -------------------------- placing -------------------------- // 3495 // -------------------------- placing -------------------------- //
3496  3496 
3497 /** 3497 /**
3498  * position a rect that will occupy space in the packer 3498  * position a rect that will occupy space in the packer
3499  * @param {Number} x 3499  * @param {Number} x
3500  * @param {Number} y 3500  * @param {Number} y
3501  * @param {Boolean} isMaxYContained 3501  * @param {Boolean} isMaxYContained
3502  */ 3502  */
3503 Item.prototype.positionPlaceRect = function( x, y, isMaxYOpen ) { 3503 Item.prototype.positionPlaceRect = function( x, y, isMaxYOpen ) {
3504   this.placeRect.x = this.getPlaceRectCoord( x, true ); 3504   this.placeRect.x = this.getPlaceRectCoord( x, true );
3505   this.placeRect.y = this.getPlaceRectCoord( y, false, isMaxYOpen ); 3505   this.placeRect.y = this.getPlaceRectCoord( y, false, isMaxYOpen );
3506 }; 3506 };
3507  3507 
3508 /** 3508 /**
3509  * get x/y coordinate for place rect 3509  * get x/y coordinate for place rect
3510  * @param {Number} coord - x or y 3510  * @param {Number} coord - x or y
3511  * @param {Boolean} isX 3511  * @param {Boolean} isX
3512  * @param {Boolean} isMaxOpen - does not limit value to outer bound 3512  * @param {Boolean} isMaxOpen - does not limit value to outer bound
3513  * @returns {Number} coord - processed x or y 3513  * @returns {Number} coord - processed x or y
3514  */ 3514  */
3515 Item.prototype.getPlaceRectCoord = function( coord, isX, isMaxOpen ) { 3515 Item.prototype.getPlaceRectCoord = function( coord, isX, isMaxOpen ) {
3516   var measure = isX ? 'Width' : 'Height'; 3516   var measure = isX ? 'Width' : 'Height';
3517   var size = this.size[ 'outer' + measure ]; 3517   var size = this.size[ 'outer' + measure ];
3518   var segment = this.layout[ isX ? 'columnWidth' : 'rowHeight' ]; 3518   var segment = this.layout[ isX ? 'columnWidth' : 'rowHeight' ];
3519   var parentSize = this.layout.size[ 'inner' + measure ]; 3519   var parentSize = this.layout.size[ 'inner' + measure ];
3520  3520 
3521   // additional parentSize calculations for Y 3521   // additional parentSize calculations for Y
3522   if ( !isX ) { 3522   if ( !isX ) {
3523     parentSize = Math.max( parentSize, this.layout.maxY ); 3523     parentSize = Math.max( parentSize, this.layout.maxY );
3524     // prevent gutter from bumping up height when non-vertical grid 3524     // prevent gutter from bumping up height when non-vertical grid
3525     if ( !this.layout.rowHeight ) { 3525     if ( !this.layout.rowHeight ) {
3526       parentSize -= this.layout.gutter; 3526       parentSize -= this.layout.gutter;
3527     } 3527     }
3528   } 3528   }
3529  3529 
3530   var max; 3530   var max;
3531  3531 
3532   if ( segment ) { 3532   if ( segment ) {
3533     segment += this.layout.gutter; 3533     segment += this.layout.gutter;
3534     // allow for last column to reach the edge 3534     // allow for last column to reach the edge
3535     parentSize += isX ? this.layout.gutter : 0; 3535     parentSize += isX ? this.layout.gutter : 0;
3536     // snap to closest segment 3536     // snap to closest segment
3537     coord = Math.round( coord / segment ); 3537     coord = Math.round( coord / segment );
3538     // contain to outer bound 3538     // contain to outer bound
3539     // contain non-growing bound, allow growing bound to grow 3539     // contain non-growing bound, allow growing bound to grow
3540     var mathMethod; 3540     var mathMethod;
3541     if ( this.layout.options.isHorizontal ) { 3541     if ( this.layout.options.isHorizontal ) {
3542       mathMethod = !isX ? 'floor' : 'ceil'; 3542       mathMethod = !isX ? 'floor' : 'ceil';
3543     } else { 3543     } else {
3544       mathMethod = isX ? 'floor' : 'ceil'; 3544       mathMethod = isX ? 'floor' : 'ceil';
3545     } 3545     }
3546     var maxSegments = Math[ mathMethod ]( parentSize / segment ); 3546     var maxSegments = Math[ mathMethod ]( parentSize / segment );
3547     maxSegments -= Math.ceil( size / segment ); 3547     maxSegments -= Math.ceil( size / segment );
3548     max = maxSegments; 3548     max = maxSegments;
3549   } else { 3549   } else {
3550     max = parentSize - size; 3550     max = parentSize - size;
3551   } 3551   }
3552  3552 
3553   coord = isMaxOpen ? coord : Math.min( coord, max ); 3553   coord = isMaxOpen ? coord : Math.min( coord, max );
3554   coord *= segment || 1; 3554   coord *= segment || 1;
3555  3555 
3556   return Math.max( 0, coord ); 3556   return Math.max( 0, coord );
3557 }; 3557 };
3558  3558 
3559 Item.prototype.copyPlaceRectPosition = function() { 3559 Item.prototype.copyPlaceRectPosition = function() {
3560   this.rect.x = this.placeRect.x; 3560   this.rect.x = this.placeRect.x;
3561   this.rect.y = this.placeRect.y; 3561   this.rect.y = this.placeRect.y;
3562 }; 3562 };
3563  3563 
3564 // -----  ----- // 3564 // -----  ----- //
3565  3565 
3566 // remove element from DOM 3566 // remove element from DOM
3567 Item.prototype.removeElem = function() { 3567 Item.prototype.removeElem = function() {
3568   this.element.parentNode.removeChild( this.element ); 3568   this.element.parentNode.removeChild( this.element );
3569   // add space back to packer 3569   // add space back to packer
3570   this.layout.packer.addSpace( this.rect ); 3570   this.layout.packer.addSpace( this.rect );
3571   this.emitEvent( 'remove', [ this ] ); 3571   this.emitEvent( 'remove', [ this ] );
3572 }; 3572 };
3573  3573 
3574 // -----  ----- // 3574 // -----  ----- //
3575  3575 
3576 return Item; 3576 return Item;
3577  3577 
3578 })); 3578 }));
3579  3579 
3580 /*! 3580 /*!
3581  * Packery v1.4.3 3581  * Packery v1.4.3
3582  * bin-packing layout library 3582  * bin-packing layout library
3583  * 3583  *
3584  * Licensed GPLv3 for open source use 3584  * Licensed GPLv3 for open source use
3585  * or Flickity Commercial License for commercial use 3585  * or Flickity Commercial License for commercial use
3586  * 3586  *
3587  * http://packery.metafizzy.co 3587  * http://packery.metafizzy.co
3588  * Copyright 2015 Metafizzy 3588  * Copyright 2015 Metafizzy
3589  */ 3589  */
3590  3590 
3591 ( function( window, factory ) { 3591 ( function( window, factory ) {
3592    3592   
3593   // universal module definition 3593   // universal module definition
3594   if ( typeof define == 'function' && define.amd ) { 3594   if ( typeof define == 'function' && define.amd ) {
3595     // AMD 3595     // AMD
3596     define( [ 3596     define( [
3597         'classie/classie', 3597         'classie/classie',
3598         'get-size/get-size', 3598         'get-size/get-size',
3599         'outlayer/outlayer', 3599         'outlayer/outlayer',
3600         'packery/js/rect', 3600         'packery/js/rect',
3601         'packery/js/packer', 3601         'packery/js/packer',
3602         'packery/js/item' 3602         'packery/js/item'
3603       ], 3603       ],
3604       factory ); 3604       factory );
3605   } else if ( typeof exports == 'object' ) { 3605   } else if ( typeof exports == 'object' ) {
3606     // CommonJS 3606     // CommonJS
3607     module.exports = factory( 3607     module.exports = factory(
3608       require('desandro-classie'), 3608       require('desandro-classie'),
3609       require('get-size'), 3609       require('get-size'),
3610       require('outlayer'), 3610       require('outlayer'),
3611       require('./rect'), 3611       require('./rect'),
3612       require('./packer'), 3612       require('./packer'),
3613       require('./item') 3613       require('./item')
3614     ); 3614     );
3615   } else { 3615   } else {
3616     // browser global 3616     // browser global
3617     window.Packery = factory( 3617     window.Packery = factory(
3618       window.classie, 3618       window.classie,
3619       window.getSize, 3619       window.getSize,
3620       window.Outlayer, 3620       window.Outlayer,
3621       window.Packery.Rect, 3621       window.Packery.Rect,
3622       window.Packery.Packer, 3622       window.Packery.Packer,
3623       window.Packery.Item 3623       window.Packery.Item
3624     ); 3624     );
3625   } 3625   }
3626  3626 
3627 }( window, function factory( classie, getSize, Outlayer, Rect, Packer, Item ) { 3627 }( window, function factory( classie, getSize, Outlayer, Rect, Packer, Item ) {
3628  3628 
3629  3629 
3630 // ----- Rect ----- // 3630 // ----- Rect ----- //
3631  3631 
3632 // allow for pixel rounding errors IE8-IE11 & Firefox; #227 3632 // allow for pixel rounding errors IE8-IE11 & Firefox; #227
3633 Rect.prototype.canFit = function( rect ) { 3633 Rect.prototype.canFit = function( rect ) {
3634   return this.width >= rect.width - 1 && this.height >= rect.height - 1; 3634   return this.width >= rect.width - 1 && this.height >= rect.height - 1;
3635 }; 3635 };
3636  3636 
3637 // -------------------------- Packery -------------------------- // 3637 // -------------------------- Packery -------------------------- //
3638  3638 
3639 // create an Outlayer layout class 3639 // create an Outlayer layout class
3640 var Packery = Outlayer.create('packery'); 3640 var Packery = Outlayer.create('packery');
3641 Packery.Item = Item; 3641 Packery.Item = Item;
3642  3642 
3643 Packery.prototype._create = function() { 3643 Packery.prototype._create = function() {
3644   // call super 3644   // call super
3645   Outlayer.prototype._create.call( this ); 3645   Outlayer.prototype._create.call( this );
3646  3646 
3647   // initial properties 3647   // initial properties
3648   this.packer = new Packer(); 3648   this.packer = new Packer();
3649  3649 
3650   // Left over from v1.0 3650   // Left over from v1.0
3651   this.stamp( this.options.stamped ); 3651   this.stamp( this.options.stamped );
3652  3652 
3653   // create drag handlers 3653   // create drag handlers
3654   var _this = this; 3654   var _this = this;
3655   this.handleDraggabilly = { 3655   this.handleDraggabilly = {
3656     dragStart: function() { 3656     dragStart: function() {
3657       _this.itemDragStart( this.element ); 3657       _this.itemDragStart( this.element );
3658     }, 3658     },
3659     dragMove: function() { 3659     dragMove: function() {
3660       _this.itemDragMove( this.element, this.position.x, this.position.y ); 3660       _this.itemDragMove( this.element, this.position.x, this.position.y );
3661     }, 3661     },
3662     dragEnd: function() { 3662     dragEnd: function() {
3663       _this.itemDragEnd( this.element ); 3663       _this.itemDragEnd( this.element );
3664     } 3664     }
3665   }; 3665   };
3666  3666 
3667   this.handleUIDraggable = { 3667   this.handleUIDraggable = {
3668     start: function handleUIDraggableStart( event, ui ) { 3668     start: function handleUIDraggableStart( event, ui ) {
3669       // HTML5 may trigger dragstart, dismiss HTML5 dragging 3669       // HTML5 may trigger dragstart, dismiss HTML5 dragging
3670       if ( !ui ) { 3670       if ( !ui ) {
3671         return; 3671         return;
3672       } 3672       }
3673       _this.itemDragStart( event.currentTarget ); 3673       _this.itemDragStart( event.currentTarget );
3674     }, 3674     },
3675     drag: function handleUIDraggableDrag( event, ui ) { 3675     drag: function handleUIDraggableDrag( event, ui ) {
3676       if ( !ui ) { 3676       if ( !ui ) {
3677         return; 3677         return;
3678       } 3678       }
3679       _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top ); 3679       _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top );
3680     }, 3680     },
3681     stop: function handleUIDraggableStop( event, ui ) { 3681     stop: function handleUIDraggableStop( event, ui ) {
3682       if ( !ui ) { 3682       if ( !ui ) {
3683         return; 3683         return;
3684       } 3684       }
3685       _this.itemDragEnd( event.currentTarget ); 3685       _this.itemDragEnd( event.currentTarget );
3686     } 3686     }
3687   }; 3687   };
3688  3688 
3689 }; 3689 };
3690  3690 
3691  3691 
3692 // ----- init & layout ----- // 3692 // ----- init & layout ----- //
3693  3693 
3694 /** 3694 /**
3695  * logic before any new layout 3695  * logic before any new layout
3696  */ 3696  */
3697 Packery.prototype._resetLayout = function() { 3697 Packery.prototype._resetLayout = function() {
3698   this.getSize(); 3698   this.getSize();
3699  3699 
3700   this._getMeasurements(); 3700   this._getMeasurements();
3701  3701 
3702   // reset packer 3702   // reset packer
3703   var packer = this.packer; 3703   var packer = this.packer;
3704   // packer settings, if horizontal or vertical 3704   // packer settings, if horizontal or vertical
3705   if ( this.options.isHorizontal ) { 3705   if ( this.options.isHorizontal ) {
3706     packer.width = Number.POSITIVE_INFINITY; 3706     packer.width = Number.POSITIVE_INFINITY;
3707     packer.height = this.size.innerHeight + this.gutter; 3707     packer.height = this.size.innerHeight + this.gutter;
3708     packer.sortDirection = 'rightwardTopToBottom'; 3708     packer.sortDirection = 'rightwardTopToBottom';
3709   } else { 3709   } else {
3710     packer.width = this.size.innerWidth + this.gutter; 3710     packer.width = this.size.innerWidth + this.gutter;
3711     packer.height = Number.POSITIVE_INFINITY; 3711     packer.height = Number.POSITIVE_INFINITY;
3712     packer.sortDirection = 'downwardLeftToRight'; 3712     packer.sortDirection = 'downwardLeftToRight';
3713   } 3713   }
3714  3714 
3715   packer.reset(); 3715   packer.reset();
3716  3716 
3717   // layout 3717   // layout
3718   this.maxY = 0; 3718   this.maxY = 0;
3719   this.maxX = 0; 3719   this.maxX = 0;
3720 }; 3720 };
3721  3721 
3722 /** 3722 /**
3723  * update columnWidth, rowHeight, & gutter 3723  * update columnWidth, rowHeight, & gutter
3724  * @private 3724  * @private
3725  */ 3725  */
3726 Packery.prototype._getMeasurements = function() { 3726 Packery.prototype._getMeasurements = function() {
3727   this._getMeasurement( 'columnWidth', 'width' ); 3727   this._getMeasurement( 'columnWidth', 'width' );
3728   this._getMeasurement( 'rowHeight', 'height' ); 3728   this._getMeasurement( 'rowHeight', 'height' );
3729   this._getMeasurement( 'gutter', 'width' ); 3729   this._getMeasurement( 'gutter', 'width' );
3730 }; 3730 };
3731  3731 
3732 Packery.prototype._getItemLayoutPosition = function( item ) { 3732 Packery.prototype._getItemLayoutPosition = function( item ) {
3733   this._packItem( item ); 3733   this._packItem( item );
3734   return item.rect; 3734   return item.rect;
3735 }; 3735 };
3736  3736 
3737  3737 
3738 /** 3738 /**
3739  * layout item in packer 3739  * layout item in packer
3740  * @param {Packery.Item} item 3740  * @param {Packery.Item} item
3741  */ 3741  */
3742 Packery.prototype._packItem = function( item ) { 3742 Packery.prototype._packItem = function( item ) {
3743   this._setRectSize( item.element, item.rect ); 3743   this._setRectSize( item.element, item.rect );
3744   // pack the rect in the packer 3744   // pack the rect in the packer
3745   this.packer.pack( item.rect ); 3745   this.packer.pack( item.rect );
3746   this._setMaxXY( item.rect ); 3746   this._setMaxXY( item.rect );
3747 }; 3747 };
3748  3748 
3749 /** 3749 /**
3750  * set max X and Y value, for size of container 3750  * set max X and Y value, for size of container
3751  * @param {Packery.Rect} rect 3751  * @param {Packery.Rect} rect
3752  * @private 3752  * @private
3753  */ 3753  */
3754 Packery.prototype._setMaxXY = function( rect ) { 3754 Packery.prototype._setMaxXY = function( rect ) {
3755   this.maxX = Math.max( rect.x + rect.width, this.maxX ); 3755   this.maxX = Math.max( rect.x + rect.width, this.maxX );
3756   this.maxY = Math.max( rect.y + rect.height, this.maxY ); 3756   this.maxY = Math.max( rect.y + rect.height, this.maxY );
3757 }; 3757 };
3758  3758 
3759 /** 3759 /**
3760  * set the width and height of a rect, applying columnWidth and rowHeight 3760  * set the width and height of a rect, applying columnWidth and rowHeight
3761  * @param {Element} elem 3761  * @param {Element} elem
3762  * @param {Packery.Rect} rect 3762  * @param {Packery.Rect} rect
3763  */ 3763  */
3764 Packery.prototype._setRectSize = function( elem, rect ) { 3764 Packery.prototype._setRectSize = function( elem, rect ) {
3765   var size = getSize( elem ); 3765   var size = getSize( elem );
3766   var w = size.outerWidth; 3766   var w = size.outerWidth;
3767   var h = size.outerHeight; 3767   var h = size.outerHeight;
3768   // size for columnWidth and rowHeight, if available 3768   // size for columnWidth and rowHeight, if available
3769   // only check if size is non-zero, #177 3769   // only check if size is non-zero, #177
3770   if ( w || h ) { 3770   if ( w || h ) {
3771     w = this._applyGridGutter( w, this.columnWidth ); 3771     w = this._applyGridGutter( w, this.columnWidth );
3772     h = this._applyGridGutter( h, this.rowHeight ); 3772     h = this._applyGridGutter( h, this.rowHeight );
3773   } 3773   }
3774   // rect must fit in packer 3774   // rect must fit in packer
3775   rect.width = Math.min( w, this.packer.width ); 3775   rect.width = Math.min( w, this.packer.width );
3776   rect.height = Math.min( h, this.packer.height ); 3776   rect.height = Math.min( h, this.packer.height );
3777 }; 3777 };
3778  3778 
3779 /** 3779 /**
3780  * fits item to columnWidth/rowHeight and adds gutter 3780  * fits item to columnWidth/rowHeight and adds gutter
3781  * @param {Number} measurement - item width or height 3781  * @param {Number} measurement - item width or height
3782  * @param {Number} gridSize - columnWidth or rowHeight 3782  * @param {Number} gridSize - columnWidth or rowHeight
3783  * @returns measurement 3783  * @returns measurement
3784  */ 3784  */
3785 Packery.prototype._applyGridGutter = function( measurement, gridSize ) { 3785 Packery.prototype._applyGridGutter = function( measurement, gridSize ) {
3786   // just add gutter if no gridSize 3786   // just add gutter if no gridSize
3787   if ( !gridSize ) { 3787   if ( !gridSize ) {
3788     return measurement + this.gutter; 3788     return measurement + this.gutter;
3789   } 3789   }
3790   gridSize += this.gutter; 3790   gridSize += this.gutter;
3791   // fit item to columnWidth/rowHeight 3791   // fit item to columnWidth/rowHeight
3792   var remainder = measurement % gridSize; 3792   var remainder = measurement % gridSize;
3793   var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; 3793   var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
3794   measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize; 3794   measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize;
3795   return measurement; 3795   return measurement;
3796 }; 3796 };
3797  3797 
3798 Packery.prototype._getContainerSize = function() { 3798 Packery.prototype._getContainerSize = function() {
3799   if ( this.options.isHorizontal ) { 3799   if ( this.options.isHorizontal ) {
3800     return { 3800     return {
3801       width: this.maxX - this.gutter 3801       width: this.maxX - this.gutter
3802     }; 3802     };
3803   } else { 3803   } else {
3804     return { 3804     return {
3805       height: this.maxY - this.gutter 3805       height: this.maxY - this.gutter
3806     }; 3806     };
3807   } 3807   }
3808 }; 3808 };
3809  3809 
3810  3810 
3811 // -------------------------- stamp -------------------------- // 3811 // -------------------------- stamp -------------------------- //
3812  3812 
3813 /** 3813 /**
3814  * makes space for element 3814  * makes space for element
3815  * @param {Element} elem 3815  * @param {Element} elem
3816  */ 3816  */
3817 Packery.prototype._manageStamp = function( elem ) { 3817 Packery.prototype._manageStamp = function( elem ) {
3818  3818 
3819   var item = this.getItem( elem ); 3819   var item = this.getItem( elem );
3820   var rect; 3820   var rect;
3821   if ( item && item.isPlacing ) { 3821   if ( item && item.isPlacing ) {
3822     rect = item.placeRect; 3822     rect = item.placeRect;
3823   } else { 3823   } else {
3824     var offset = this._getElementOffset( elem ); 3824     var offset = this._getElementOffset( elem );
3825     rect = new Rect({ 3825     rect = new Rect({
3826       x: this.options.isOriginLeft ? offset.left : offset.right, 3826       x: this.options.isOriginLeft ? offset.left : offset.right,
3827       y: this.options.isOriginTop ? offset.top : offset.bottom 3827       y: this.options.isOriginTop ? offset.top : offset.bottom
3828     }); 3828     });
3829   } 3829   }
3830  3830 
3831   this._setRectSize( elem, rect ); 3831   this._setRectSize( elem, rect );
3832   // save its space in the packer 3832   // save its space in the packer
3833   this.packer.placed( rect ); 3833   this.packer.placed( rect );
3834   this._setMaxXY( rect ); 3834   this._setMaxXY( rect );
3835 }; 3835 };
3836  3836 
3837 // -------------------------- methods -------------------------- // 3837 // -------------------------- methods -------------------------- //
3838  3838 
3839 function verticalSorter( a, b ) { 3839 function verticalSorter( a, b ) {
3840   return a.position.y - b.position.y || a.position.x - b.position.x; 3840   return a.position.y - b.position.y || a.position.x - b.position.x;
3841 } 3841 }
3842  3842 
3843 function horizontalSorter( a, b ) { 3843 function horizontalSorter( a, b ) {
3844   return a.position.x - b.position.x || a.position.y - b.position.y; 3844   return a.position.x - b.position.x || a.position.y - b.position.y;
3845 } 3845 }
3846  3846 
3847 Packery.prototype.sortItemsByPosition = function() { 3847 Packery.prototype.sortItemsByPosition = function() {
3848   var sorter = this.options.isHorizontal ? horizontalSorter : verticalSorter; 3848   var sorter = this.options.isHorizontal ? horizontalSorter : verticalSorter;
3849   this.items.sort( sorter ); 3849   this.items.sort( sorter );
3850 }; 3850 };
3851  3851 
3852 /** 3852 /**
3853  * Fit item element in its current position 3853  * Fit item element in its current position
3854  * Packery will position elements around it 3854  * Packery will position elements around it
3855  * useful for expanding elements 3855  * useful for expanding elements
3856  * 3856  *
3857  * @param {Element} elem 3857  * @param {Element} elem
3858  * @param {Number} x - horizontal destination position, optional 3858  * @param {Number} x - horizontal destination position, optional
3859  * @param {Number} y - vertical destination position, optional 3859  * @param {Number} y - vertical destination position, optional
3860  */ 3860  */
3861 Packery.prototype.fit = function( elem, x, y ) { 3861 Packery.prototype.fit = function( elem, x, y ) {
3862   var item = this.getItem( elem ); 3862   var item = this.getItem( elem );
3863   if ( !item ) { 3863   if ( !item ) {
3864     return; 3864     return;
3865   } 3865   }
3866  3866 
3867   // prepare internal properties 3867   // prepare internal properties
3868   this._getMeasurements(); 3868   this._getMeasurements();
3869  3869 
3870   // stamp item to get it out of layout 3870   // stamp item to get it out of layout
3871   this.stamp( item.element ); 3871   this.stamp( item.element );
3872   // required for positionPlaceRect 3872   // required for positionPlaceRect
3873   item.getSize(); 3873   item.getSize();
3874   // set placing flag 3874   // set placing flag
3875   item.isPlacing = true; 3875   item.isPlacing = true;
3876   // fall back to current position for fitting 3876   // fall back to current position for fitting
3877   x = x === undefined ? item.rect.x: x; 3877   x = x === undefined ? item.rect.x: x;
3878   y = y === undefined ? item.rect.y: y; 3878   y = y === undefined ? item.rect.y: y;
3879  3879 
3880   // position it best at its destination 3880   // position it best at its destination
3881   item.positionPlaceRect( x, y, true ); 3881   item.positionPlaceRect( x, y, true );
3882  3882 
3883   this._bindFitEvents( item ); 3883   this._bindFitEvents( item );
3884   item.moveTo( item.placeRect.x, item.placeRect.y ); 3884   item.moveTo( item.placeRect.x, item.placeRect.y );
3885   // layout everything else 3885   // layout everything else
3886   this.layout(); 3886   this.layout();
3887  3887 
3888   // return back to regularly scheduled programming 3888   // return back to regularly scheduled programming
3889   this.unstamp( item.element ); 3889   this.unstamp( item.element );
3890   this.sortItemsByPosition(); 3890   this.sortItemsByPosition();
3891   // un set placing flag, back to normal 3891   // un set placing flag, back to normal
3892   item.isPlacing = false; 3892   item.isPlacing = false;
3893   // copy place rect position 3893   // copy place rect position
3894   item.copyPlaceRectPosition(); 3894   item.copyPlaceRectPosition();
3895 }; 3895 };
3896  3896 
3897 /** 3897 /**
3898  * emit event when item is fit and other items are laid out 3898  * emit event when item is fit and other items are laid out
3899  * @param {Packery.Item} item 3899  * @param {Packery.Item} item
3900  * @private 3900  * @private
3901  */ 3901  */
3902 Packery.prototype._bindFitEvents = function( item ) { 3902 Packery.prototype._bindFitEvents = function( item ) {
3903   var _this = this; 3903   var _this = this;
3904   var ticks = 0; 3904   var ticks = 0;
3905   function tick() { 3905   function tick() {
3906     ticks++; 3906     ticks++;
3907     if ( ticks != 2 ) { 3907     if ( ticks != 2 ) {
3908       return; 3908       return;
3909     } 3909     }
3910     _this.dispatchEvent( 'fitComplete', null, [ item ] ); 3910     _this.dispatchEvent( 'fitComplete', null, [ item ] );
3911   } 3911   }
3912   // when item is laid out 3912   // when item is laid out
3913   item.on( 'layout', function() { 3913   item.on( 'layout', function() {
3914     tick(); 3914     tick();
3915     return true; 3915     return true;
3916   }); 3916   });
3917   // when all items are laid out 3917   // when all items are laid out
3918   this.on( 'layoutComplete', function() { 3918   this.on( 'layoutComplete', function() {
3919     tick(); 3919     tick();
3920     return true; 3920     return true;
3921   }); 3921   });
3922 }; 3922 };
3923  3923 
3924 // -------------------------- resize -------------------------- // 3924 // -------------------------- resize -------------------------- //
3925  3925 
3926 // debounced, layout on resize 3926 // debounced, layout on resize
3927 Packery.prototype.resize = function() { 3927 Packery.prototype.resize = function() {
3928   // don't trigger if size did not change 3928   // don't trigger if size did not change
3929   var size = getSize( this.element ); 3929   var size = getSize( this.element );
3930   // check that this.size and size are there 3930   // check that this.size and size are there
3931   // IE8 triggers resize on body size change, so they might not be 3931   // IE8 triggers resize on body size change, so they might not be
3932   var hasSizes = this.size && size; 3932   var hasSizes = this.size && size;
3933   var innerSize = this.options.isHorizontal ? 'innerHeight' : 'innerWidth'; 3933   var innerSize = this.options.isHorizontal ? 'innerHeight' : 'innerWidth';
3934   if ( hasSizes && size[ innerSize ] == this.size[ innerSize ] ) { 3934   if ( hasSizes && size[ innerSize ] == this.size[ innerSize ] ) {
3935     return; 3935     return;
3936   } 3936   }
3937  3937 
3938   this.layout(); 3938   this.layout();
3939 }; 3939 };
3940  3940 
3941 // -------------------------- drag -------------------------- // 3941 // -------------------------- drag -------------------------- //
3942  3942 
3943 /** 3943 /**
3944  * handle an item drag start event 3944  * handle an item drag start event
3945  * @param {Element} elem 3945  * @param {Element} elem
3946  */ 3946  */
3947 Packery.prototype.itemDragStart = function( elem ) { 3947 Packery.prototype.itemDragStart = function( elem ) {
3948   this.stamp( elem ); 3948   this.stamp( elem );
3949   var item = this.getItem( elem ); 3949   var item = this.getItem( elem );
3950   if ( item ) { 3950   if ( item ) {
3951     item.dragStart(); 3951     item.dragStart();
3952   } 3952   }
3953 }; 3953 };
3954  3954 
3955 /** 3955 /**
3956  * handle an item drag move event 3956  * handle an item drag move event
3957  * @param {Element} elem 3957  * @param {Element} elem
3958  * @param {Number} x - horizontal change in position 3958  * @param {Number} x - horizontal change in position
3959  * @param {Number} y - vertical change in position 3959  * @param {Number} y - vertical change in position
3960  */ 3960  */
3961 Packery.prototype.itemDragMove = function( elem, x, y ) { 3961 Packery.prototype.itemDragMove = function( elem, x, y ) {
3962   var item = this.getItem( elem ); 3962   var item = this.getItem( elem );
3963   if ( item ) { 3963   if ( item ) {
3964     item.dragMove( x, y ); 3964     item.dragMove( x, y );
3965   } 3965   }
3966  3966 
3967   // debounce 3967   // debounce
3968   var _this = this; 3968   var _this = this;
3969   // debounce triggering layout 3969   // debounce triggering layout
3970   function delayed() { 3970   function delayed() {
3971     _this.layout(); 3971     _this.layout();
3972     delete _this.dragTimeout; 3972     delete _this.dragTimeout;
3973   } 3973   }
3974  3974 
3975   this.clearDragTimeout(); 3975   this.clearDragTimeout();
3976  3976 
3977   this.dragTimeout = setTimeout( delayed, 40 ); 3977   this.dragTimeout = setTimeout( delayed, 40 );
3978 }; 3978 };
3979  3979 
3980 Packery.prototype.clearDragTimeout = function() { 3980 Packery.prototype.clearDragTimeout = function() {
3981   if ( this.dragTimeout ) { 3981   if ( this.dragTimeout ) {
3982     clearTimeout( this.dragTimeout ); 3982     clearTimeout( this.dragTimeout );
3983   } 3983   }
3984 }; 3984 };
3985  3985 
3986 /** 3986 /**
3987  * handle an item drag end event 3987  * handle an item drag end event
3988  * @param {Element} elem 3988  * @param {Element} elem
3989  */ 3989  */
3990 Packery.prototype.itemDragEnd = function( elem ) { 3990 Packery.prototype.itemDragEnd = function( elem ) {
3991   var item = this.getItem( elem ); 3991   var item = this.getItem( elem );
3992   var itemDidDrag; 3992   var itemDidDrag;
3993   if ( item ) { 3993   if ( item ) {
3994     itemDidDrag = item.didDrag; 3994     itemDidDrag = item.didDrag;
3995     item.dragStop(); 3995     item.dragStop();
3996   } 3996   }
3997   // if elem didn't move, or if it doesn't need positioning 3997   // if elem didn't move, or if it doesn't need positioning
3998   // unignore and unstamp and call it a day 3998   // unignore and unstamp and call it a day
3999   if ( !item || ( !itemDidDrag && !item.needsPositioning ) ) { 3999   if ( !item || ( !itemDidDrag && !item.needsPositioning ) ) {
4000     this.unstamp( elem ); 4000     this.unstamp( elem );
4001     return; 4001     return;
4002   } 4002   }
4003   // procced with dragged item 4003   // procced with dragged item
4004  4004 
4005   classie.add( item.element, 'is-positioning-post-drag' ); 4005   classie.add( item.element, 'is-positioning-post-drag' );
4006  4006 
4007   // save this var, as it could get reset in dragStart 4007   // save this var, as it could get reset in dragStart
4008   var onLayoutComplete = this._getDragEndLayoutComplete( elem, item ); 4008   var onLayoutComplete = this._getDragEndLayoutComplete( elem, item );
4009  4009 
4010   if ( item.needsPositioning ) { 4010   if ( item.needsPositioning ) {
4011     item.on( 'layout', onLayoutComplete ); 4011     item.on( 'layout', onLayoutComplete );
4012     item.moveTo( item.placeRect.x, item.placeRect.y ); 4012     item.moveTo( item.placeRect.x, item.placeRect.y );
4013   } else if ( item ) { 4013   } else if ( item ) {
4014     // item didn't need placement 4014     // item didn't need placement
4015     item.copyPlaceRectPosition(); 4015     item.copyPlaceRectPosition();
4016   } 4016   }
4017  4017 
4018   this.clearDragTimeout(); 4018   this.clearDragTimeout();
4019   this.on( 'layoutComplete', onLayoutComplete ); 4019   this.on( 'layoutComplete', onLayoutComplete );
4020   this.layout(); 4020   this.layout();
4021  4021 
4022 }; 4022 };
4023  4023 
4024 /** 4024 /**
4025  * get drag end callback 4025  * get drag end callback
4026  * @param {Element} elem 4026  * @param {Element} elem
4027  * @param {Packery.Item} item 4027  * @param {Packery.Item} item
4028  * @returns {Function} onLayoutComplete 4028  * @returns {Function} onLayoutComplete
4029  */ 4029  */
4030 Packery.prototype._getDragEndLayoutComplete = function( elem, item ) { 4030 Packery.prototype._getDragEndLayoutComplete = function( elem, item ) {
4031   var itemNeedsPositioning = item && item.needsPositioning; 4031   var itemNeedsPositioning = item && item.needsPositioning;
4032   var completeCount = 0; 4032   var completeCount = 0;
4033   var asyncCount = itemNeedsPositioning ? 2 : 1; 4033   var asyncCount = itemNeedsPositioning ? 2 : 1;
4034   var _this = this; 4034   var _this = this;
4035  4035 
4036   return function onLayoutComplete() { 4036   return function onLayoutComplete() {
4037     completeCount++; 4037     completeCount++;
4038     // don't proceed if not complete 4038     // don't proceed if not complete
4039     if ( completeCount != asyncCount ) { 4039     if ( completeCount != asyncCount ) {
4040       return true; 4040       return true;
4041     } 4041     }
4042     // reset item 4042     // reset item
4043     if ( item ) { 4043     if ( item ) {
4044       classie.remove( item.element, 'is-positioning-post-drag' ); 4044       classie.remove( item.element, 'is-positioning-post-drag' );
4045       item.isPlacing = false; 4045       item.isPlacing = false;
4046       item.copyPlaceRectPosition(); 4046       item.copyPlaceRectPosition();
4047     } 4047     }
4048  4048 
4049     _this.unstamp( elem ); 4049     _this.unstamp( elem );
4050     // only sort when item moved 4050     // only sort when item moved
4051     _this.sortItemsByPosition(); 4051     _this.sortItemsByPosition();
4052  4052 
4053     // emit item drag event now that everything is done 4053     // emit item drag event now that everything is done
4054     if ( itemNeedsPositioning ) { 4054     if ( itemNeedsPositioning ) {
4055       _this.dispatchEvent( 'dragItemPositioned', null, [ item ] ); 4055       _this.dispatchEvent( 'dragItemPositioned', null, [ item ] );
4056     } 4056     }
4057     // listen once 4057     // listen once
4058     return true; 4058     return true;
4059   }; 4059   };
4060 }; 4060 };
4061  4061 
4062 /** 4062 /**
4063  * binds Draggabilly events 4063  * binds Draggabilly events
4064  * @param {Draggabilly} draggie 4064  * @param {Draggabilly} draggie
4065  */ 4065  */
4066 Packery.prototype.bindDraggabillyEvents = function( draggie ) { 4066 Packery.prototype.bindDraggabillyEvents = function( draggie ) {
4067   draggie.on( 'dragStart', this.handleDraggabilly.dragStart ); 4067   draggie.on( 'dragStart', this.handleDraggabilly.dragStart );
4068   draggie.on( 'dragMove', this.handleDraggabilly.dragMove ); 4068   draggie.on( 'dragMove', this.handleDraggabilly.dragMove );
4069   draggie.on( 'dragEnd', this.handleDraggabilly.dragEnd ); 4069   draggie.on( 'dragEnd', this.handleDraggabilly.dragEnd );
4070 }; 4070 };
4071  4071 
4072 /** 4072 /**
4073  * binds jQuery UI Draggable events 4073  * binds jQuery UI Draggable events
4074  * @param {jQuery} $elems 4074  * @param {jQuery} $elems
4075  */ 4075  */
4076 Packery.prototype.bindUIDraggableEvents = function( $elems ) { 4076 Packery.prototype.bindUIDraggableEvents = function( $elems ) {
4077   $elems 4077   $elems
4078     .on( 'dragstart', this.handleUIDraggable.start ) 4078     .on( 'dragstart', this.handleUIDraggable.start )
4079     .on( 'drag', this.handleUIDraggable.drag ) 4079     .on( 'drag', this.handleUIDraggable.drag )
4080     .on( 'dragstop', this.handleUIDraggable.stop ); 4080     .on( 'dragstop', this.handleUIDraggable.stop );
4081 }; 4081 };
4082  4082 
4083 Packery.Rect = Rect; 4083 Packery.Rect = Rect;
4084 Packery.Packer = Packer; 4084 Packery.Packer = Packer;
4085  4085 
4086 return Packery; 4086 return Packery;
4087  4087 
4088 })); 4088 }));
4089  4089